为什么您不应该在JSX props中使用内联箭头功能
在JSX中使用箭头函数或绑定是不利于性能的不良做法,因为该函数会在每个渲染器上重新创建。
每当创建一个函数时,就会对前一个函数进行垃圾回收。渲染许多元素可能会在动画中产生垃圾。
使用内联箭头功能将导致
PureComponent
s和shallowCompare
该shouldComponentUpdate
方法中使用的组件重新渲染。由于箭头函数prop每次都会重新创建,因此浅表比较会将其标识为对prop的更改,并且组件将重新呈现。
在下面的两个示例中可以看到-当我们使用嵌入式箭头功能时,
<Button>每次都会重新渲染组件(控制台显示“渲染按钮”文本)。
示例1- 不带 内联处理程序的PureComponent
class Button extends React.PureComponent { render() { const { onClick } = this.props; console.log('render button'); return ( <button onClick={ onClick }>Click</button> ); }}class Parent extends React.Component { state = { counter: 0 } onClick = () => this.setState((prevState) => ({ counter: prevState.counter + 1 })); render() { const { counter } = this.state; return ( <div> <Button onClick={ this.onClick } /> <div>{ counter }</div> </div> ); }}ReactDOM.render( <Parent />, document.getElementById('root'));<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script><div id="root"></div>示例2- 具有 内联处理程序的PureComponent
class Button extends React.PureComponent { render() { const { onClick } = this.props; console.log('render button'); return ( <button onClick={ onClick }>Click</button> ); }}class Parent extends React.Component { state = { counter: 0 } render() { const { counter } = this.state; return ( <div> <Button onClick={ () => this.setState((prevState) => ({ counter: prevState.counter + 1 })) } /> <div>{ counter }</div> </div> ); }}ReactDOM.render( <Parent />, document.getElementById('root'));<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script><div id="root"></div>this
不带内联箭头功能的绑定方法
在构造函数中手动绑定方法:
class Button extends React.Component {constructor(props, context) {
super(props, context);this.cb = this.cb.bind(this);
}
cb() {
}
render() {
return (
);
}
}使用带有箭头功能的proposal-class-fields绑定方法。由于这是第3阶段的建议,因此您需要添加第3阶段的预设或将Class属性转换为babel配置。
class Button extends React.Component {cb = () => { // the class property is initialized with an arrow function that binds this to the class
}
render() {
return (
);
}
}
具有内部回调的功能组件
当我们在函数组件内部创建内部函数(例如事件处理程序)时,每次渲染组件时都会重新创建该函数。如果将函数作为道具(或通过上下文)传递给子组件(
Button在这种情况下),则该子组件也会重新渲染。
示例1-具有内部回调的功能组件:
const { memo, useState } = React;const Button = memo(({ onClick }) => console.log('render button') || ( <button onClick={onClick}>Click</button>));const Parent = () => { const [counter, setCounter] = useState(0); const increment = () => setCounter(counter => counter + 1); // the function is recreated all the time return ( <div> <Button onClick={increment} /> <div>{counter}</div> </div> );}ReactDOM.render( <Parent />, document.getElementById('root'));<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><div id="root"></div>为了解决这个问题,我们可以使用
useCallback()hook来包装回调,并将依赖项设置为一个空数组。
注意: 在
useState生成函数接受更新器功能,其提供当前状态。这样,我们无需将当前状态设置为的依赖项
useCallback。
示例2-具有内部回调的函数组件,该内部回调包装有useCallback:
const { memo, useState, useCallback } = React;const Button = memo(({ onClick }) => console.log('render button') || ( <button onClick={onClick}>Click</button>));const Parent = () => { const [counter, setCounter] = useState(0); const increment = useCallback(() => setCounter(counter => counter + 1), []); return ( <div> <Button onClick={increment} /> <div>{counter}</div> </div> );}ReactDOM.render( <Parent />, document.getElementById('root'));<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><div id="root"></div>


