首先放个总图:
其实绝大多数的内容相信大家已经很了解了,不过我们来重点看看这几个钩子函数:
componentWillMount
componentDidMount
componentWillReceiveProps
shouldComponentUpdate
关于前两个我想讲的是关于ajax获取数据究竟是放在WillMount还是DidMount,相信很多文章已经给过答案了,就是放在DidMount中。
React会在组件第一次执行render方法前执行这个方法,乍一看它是处理获取数据逻辑的很完美的地方。但是我们一般都是通过异步请求API的方式来获取数据,这就意味着我们还没有获取到数据而render方法已经被执行了,所以我们没有办法暂停render的执行来等待数据的到来。-
关于componentWillReceiveProps,这个确实有些绕人的坑,下面是详解:
- 首先想要这个函数执行要有一个硬性条件,那就是子组件必须接收父组件的props。
- 只要父组件的render函数被重新执行,注意,是重新执行,也就是说父组件的第一次render
不会触发这个函数,只有大于等于第二次,子组件的componentWillReceiveProps才会被执行。
换句话说,也就是如果子组件第一次被渲染在于父组件中,componentWillReceiveProps不会被执行,如果子组件之前就在父组件中被渲染过,componentWillReceiveProps才会被执行。
-
下面来谈谈shouldComponentUpdate,这个函数使用起来很简单:
shouldComponentUpdate() { return true or false }
也就是说当一个子组件接收到父组件传递的参数,需要更改数据时,在子组件里可以设置这个函数,return true时子组件将被重新渲染,而false则不做改动。
下面谈谈使用场景,举个例子,假设我们做一个todolist,在input中输入todo的项目,点击提交按钮,再通过子组件列表一一展现输入的项目:
//父组件 this.state = { inputValue : '', list:[] } handleInputChange:(e)=>{ const value = e.target.value this.setState({ inputValue: value } handleButtonClick:()=>{ this.setState((prevState)=>{ list: [...prevState.list, prevState.inputValue], inputValue: '' }) } render() { return ( <div> <input onChange={this.handleInputChange} value={this.state.inputValue}/> <button onClick={this.handleButtonClick}/> <ul> { this.state.list.map((item, index)=>{ <TodoItem item='item'/> }) } </ul> </div> ) }
//子组件 render() { const {item} = this.props return <li>{item}</li> }
这时会遇到一个问题,当我们在input框输入内容的时候,会触发input框的onChange事件,由于onChange事件关联了state中的inputValue数据,所以数据一变化render函数就会被执行,而父组件的render函数一执行,子组件的render也要被执行,这就导致了我们在父组件的input框中输入值的时候,每输入内容父组件和之前输入已经展示在页面子组件都会被重新渲染,那么怎么做性能优化呢?我们可以在子组件中加上:
shouldComponentUpdate() { return false }
这时当我们在input框里随便输入字符时候,已存在页面上的子组件就不会被重新渲染了,而父组件点提交时,子组件并不受影响,照常可以新增在ul中,因为是新的子组件(每按一次提交,都是生成一个新的<li>子组件),因此不会触发shouldComponentUpdate,由此提升了页面性能。但是这么写并不严谨,我们可以加一些判断,如下:
shouldComponentUpdate(nextProps, nextState) { if(nextProps.item!=this.props.item) { return true } return false }
shouldComponentUpdate接收两个参数,nextProps指接下来props会变化成什么样,nextState同理,这里我们的子组件接收的是item这个内容,当item没有变化,组件就不需要重新渲染(本例的item无论如何也不会变化,父组件并未对已经传递给子组件的item做改动,这样写只是严谨一些,具体还是要根据业务逻辑)。