React的组件发展

函数式组件

function HelloMessage() {
  let message = 'hello message'
  return (
    <div>
      <div>{messgae}</div>
      <button onClick={() => { message = 'hello react' }}>修改文本</button>
    </div>
  )
}

函数式组件的缺陷:

  1. 组件不会重新渲染:修改message之后,组件不知道自己要重新渲染
  2. 如果组件可以重新渲染,函数会被重新执行,第二次执行时message又会被初始化为"hello message"
  3. 没有生命周期的回调

类组件

function HelloWorld (props) {
  const imitateRequest = () => {
    setTimeout(() => {
      console.log('模拟函数式组件发送请求')
    }, 1000)
  }
  imitateRequest()
  return (
    <div>
      <h2>Hello World: {props.counter}</h2>
    </div>
  )
}

class App extends PureComponent {
  constructor (props) {
    super(props)
    this.state = {
      counter: 1
    }
  }
  increment () {
    this.setState({
      counter: this.state.counter + 1
    })
  }
  render() {
    let { counter } = this.state
    return (
      <div>
        <h1>App:{counter}</h1>
        <button onClick={this.increment}>修改counter</button>
        <HelloWorld counter={counter}/>
      </div>
    )
  }
}

class组件相对于函数式组件有什么优势?比较常见的是下面的优势:

  • class可以定义自己的state,用来保存组件内部的状态

    • 而函数式组件不可以,因为函数每次调用,都会产生新的临时变量
  • class有自己的生命周期,我们可以在对应的生命周期中编写自己的逻辑

    • 比如在componentDidMount中发送网络请求,这个生命周期只会执行一次
    • 函数式组件,如果在函数中发送网络请求,每次重新渲染都会重新发送一次网络请求
  • class组件在状态发生变化时,只会重新执行render函数和componentDidupdate等

    • 函数式组件在重新渲染时,整个函数都会被执行

class组件的缺点:

  • 复杂组件变得难以理解:

  • 对于逻辑复杂的组件,代码会比较混乱,比如componentDidMount中,就可能包含大量的逻辑代码,比如网络请求,事件监听等。如果想要抽取通用的逻辑,比如高阶组件(HOC),又增加代码的复杂度。

  • 难以理解的class: 要学习class,还必须搞清楚this的指向

  • 组件复用状态很难:

    • 通过高阶组件复用状态
    • Provider和Consumer来共享状态,但是多次使用Consumer时,代码就会存在很多嵌套
    • 这些代码不管是编写和设计,都比较困难

Hooks的出现

hooks的出现解决函数式组件的问题,可以让我们在函数式组件中使用state以及react的其他特性。

const Home = () => {
  const [name, setName] = useState('hello title')
  const handleName = ({ target: {value}}) => {
    setName(value)
  }
  useEffect(() => {
    document.title = name
  }, [name])

  const [width, setWidth] = useState(window.innerWidth)
  useEffect(() => {
    let handleResize = () => setWidth(window.innerWidth)
    window.addEventListener('resize', handleResize)
    return () => {
      window.removeEventListener('resize', handleResize)
    }
  }, [])

  return (
    <div>
      <input value={name} onChange={handleName}/>
      <span>{width}</span>
    </div>
  )
}

Hooks的好处:

  • 函数式组件结合hooks让整个代码变得非常简洁

    • 利用useEffect,把业务逻辑分开,把之前放在不同生命周期里的相同功能的代码,聚合在一起,把不同功能但是要在同一生命周期的代码,隔离开,提高了代码的可读性和可维护性。
  • 解决了和状态相关的逻辑复用问题:

    • 原来代码复用使用的高阶组件和渲染属性都会增加组件树层级,使用起来也不方便,自定义hooks就可以解决这些问题,而且使用更直观方便;
  • 并且再也不用考虑this相关的问题;

  • 更好的体现了react的开发思想,从state->view的函数式映射

    • 可以把UI的展示看成一个函数执行的过程,Model就相当于输入的参数,UI就相当于函数的执行结果;react要保证的是每当状态发生变化时,函数就会重新执行,并且会生成新的dom树,然后react会把新的dom树,以最优的方式更新到浏览器上;

Hooks的注意事项:

  • 只能在函数最外层调用hook,不能在循环、条件判断或者子函数中调用
  • 只能在React的函数组件或者自定义Hooks中调用Hook,不能在其他js函数中调用
  • 保证状态最小化,需要渲染到UI里的保存在state里,不需要渲染的可以保存在useRef里;或者一些可以通过其他状态计算得出的数据;
  • 不要用props去初始化state,可以在useEffect中通过监听props的变化去设置state;

有了Hooks以后得函数式组件,依然存在一些问题:

  • 事件处理函数会被重复定义,数据计算过程没有缓存

    • 这些问题就需要利用useCallback、useMemo、useRef这些Hook来做一些优化
  • 对一些类组件的生命周期函数还不支持,还不能实现getSnapShotBeforeUpdate和componentDidCatch这个生命周期;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一. 组件化开发 组件化开发的思想 1. 分而治之的思想 人面对复杂问题的处理方式: 任何一个人处理信息的逻辑能力...
    JackLeeVip阅读 3,838评论 2 3
  • Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他...
    虚拟J阅读 5,619评论 0 1
  • 组件的生命周期 React中组件也有生命周期,也就是说也有很多钩子函数供我们使用, 组件的生命周期,我们会分为四个...
    解勾股阅读 4,055评论 0 0
  • React中组件也有生命周期,也就是说也有很多钩子函数供我们使用, 组件的生命周期,我们会分为四个阶段,初始化、运...
    周南安阅读 1,631评论 0 1
  • 组件化开发一 目前,前端三大框架(Vue,React,Angular)都在使用组件化的我形式进行开发。19年最火的...
    wpLishuai阅读 2,635评论 0 0