正常情况下,父组件状态发生变化重新渲染,会导致子组件也重新渲染,即使子组件依赖的属性在父组件中没有发生改变。
一、shouldComponentUpdate(nextProps, nextState)
此方法基本不使用。
可以通过子组件的props与nextProps进行对比,如果值相等,则不渲染
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class Child extends Component {
shouldComponentUpdate(nextProps) { if (this.props.name === nextProps.name) { return false; } return true; }
render() { console.log('child render') return ( <h3> childComponent: {this.props.name} </h3> ) } }
export default class MemoComponent extends Component {
state = { count: 1 }
handleAdd = () => { this.setState({ count: this.state.count + 1 }) }
render() { console.log('render') const { count } = this.state; return ( <div> Count: {count} <button onClick={this.handleAdd}>Add</button> <div> <Child name={'张三'}/> </div> </div> ) } }
|
二、PureComponent
class组件中shouldComponentUpdate方法的替代品
1 2 3 4 5 6 7 8 9 10 11
| class Child extends PureComponent {
render() { console.log('child render') return ( <h3> childComponent: {this.props.name} </h3> ) } }
|
只要父组件的name属性没发生改变,就不会重新渲染Child组件。
但是如果父组件传递的属性值是function或object,情况就有所不同
情况一:子组件还是会重新渲染fn
1 2 3 4 5 6 7 8
| export default class MemoComponent extends Component {
render() { return ( <Child name={'张三'} fn={() => {}}/> ) } }
|
情况二:子组件不会重新渲染fn
1 2 3 4 5 6 7 8 9 10
| export default class MemoComponent extends Component {
callback = () => { }
render() { return ( <Child name={'张三'} fn={this.callback}/> ) } }
|
情况三:子组件不会重新渲染object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| export default class MemoComponent extends Component {
state = { person: { name: 'xiaoming', age: 18 } }
changeAge = () => { this.setState({ person: { name: 'xiaoming', age: this.state.person.age + 1 } }) }
callback = () => { }
render() { console.log('render') const { person } = this.state;
return ( <div> <Child name={person.name}/> <button onClick={this.changeAge}>Change</button> </div> ) } }
class Child extends PureComponent {
render() { console.log('child render') return ( <h3> childComponent: {this.props.name} </h3> ) } }
|
三、memo
用于函数组件。是class组件中PureComponent的替代品
1 2 3 4 5 6 7 8
| const Child = memo(({ name }) => { console.log('child render') return ( <h3> childComponent: {name} </h3> ) })
|
四、useMemo 缓存一个值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| const CallBackAndMemo = () => {
const [count, setCount] = useState(0); const [flag, setFlag] = useState(false);
return ( <> <Child count={count} flag={flag} /> <button onClick={() => setCount(count + 1)}>Add</button> <button onClick={() => setFlag(!flag)}>Toggle</button> </> ) }
const convert = (flag) => { console.log('convert') return flag ? 'AAA' : 'BBB'; }
const Child = ({ count, flag }) => { const name = convert(flag);
return ( <> <p>count: {count}</p> <p>name: {name}</p> </> ) }
|
每次更改父组件的count或者flag属性时,都会重新调用convert方法。(上)
1 2 3 4 5 6 7 8 9 10 11 12
| const Child = ({ count, flag }) => { const name = useMemo(() => { return convert(flag) }, [flag]);
return ( <> <p>count: {count}</p> <p>name: {name}</p> </> ) }
|
使用useMemo(() =>{}, [])可以将name值缓存起来,或者传入依赖项,只有在依赖项发生变化时,才会重新调用convert方法。(上)
五、useCallback 缓存一个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const Child = ({ count, flag }) => {
const convert = useCallback(() => { console.log('convert', flag) return flag ? 'AAA' : 'BBB'; }, [flag])
const name = convert(flag);
return ( <> <p>count: {count}</p> <p>name: {name}</p> </> ) }
|
useCallback 的功能完全可以由 useMemo 所取代。唯一的区别是:**==useCallback 不会执行第一个参数函数,而是将它返回给你,而 useMemo 会执行第一个函数并且将函数执行结果返回给你==**。
![image]()