需要在反应Hooks
的功能组件中具有功能。
据我研究,很多人都说这是不好的做法 因为它会在我们每次调用re-render时创建嵌套/内部函数。 经过分析,
我发现我们可以在元素上使用onClick={handleClick.bind(null, props)}
并将功能放置在功能组件之外。
示例:
const HelloWorld = () => {
function handleClick = (event) => {
console.log(event.target.value);
}
return() {
<>
<input type="text" onChange={handleClick}/>
</>
}
}
请告知是否还有其他方法。
谢谢。
答案 0 :(得分:4)
您可以使用useCallback
功能:
const HelloWorld = ({ dispatch }) => {
const handleClick = useCallback((event) => {
dispatch(() => {console.log(event.target.value)}0;
})
return() {
<>
<input type="name" onChange={handleClick}/>
</>
}
}
useCallback
将返回回调的记忆版本,该回调仅 如果依赖项之一已更改,则更改。这在以下情况下很有用 将回调传递给依赖引用的优化子组件 相等以防止不必要的渲染(例如shouldComponentUpdate)。
有关更多详细信息,请访问其参考链接:React useCallback
旧方法也有两个选择。
第一个解决方案:
将您的handleClick
函数传递给功能组件。
const HelloWorld = (props) => {
return() {
<>
<input type="name" onChange={props.handleClick}/>
</>
}
}
第二个解决方案: 在功能组件之外定义功能。
答案 1 :(得分:4)
不用担心在每个渲染器上创建新功能。仅在极少数情况下会妨碍您的表现。
设置onClick
处理函数不是其中之一,因此只需在每个渲染器上创建一个新函数。
但是,当需要确保每次都使用相同的功能时,可以使用useCallaback
useCallback
使用onClick
这就是为什么您不应该为useCallback
处理程序(和大多数其他事件处理程序)而烦恼onClick
的原因。
考虑以下代码片段,其中一个没有useCallback:
function Comp(props) {
return <button onClick={() => console.log("clicked", props.foo)}>Text</Button>
}
和一个带有useCallback的
function Comp(props) {
const onClick = useCallback(() => {
console.log("clicked", props.foo)
}, [props.foo])
return <button onClick={onClick}>Text</Button>
}
后者的唯一区别是React doen拥有
如果onClick
保持不变,则更改按钮上的props.foo
。
更改回调是一项非常便宜的操作,而且完全没有
值得在代码上进行理论上的改进以使代码复杂化。
此外,值得注意的是每个渲染器上仍会创建一个新功能
即使您使用useCallback
,但useCallback
仍会返回旧的
只要作为第二个参数传递的依赖性不变。
useCallback
使用useCallback
的要点是,如果您将两个函数与引用进行比较
相等,fn === fn2
仅在fn
和fn2
指向内存中的同一函数时才为真。
函数是否是否相同都没关系。
因此,如果您有备忘录或仅在功能更改时才运行代码,
再次使用useCallback
可以使用相同的功能。
作为示例,React钩子使用probably比较旧依赖和新依赖,Object.is。
另一个例子是React.PureComponent,它只会在道具或状态改变时重新渲染。这对于使用大量资源进行渲染的组件很有用。通过例如在每个渲染器上为PureComponent新建一个onClick
都会使它每次都重新渲染。
答案 2 :(得分:3)
许多人都说这是一种不好的做法,因为每次我们称为重新渲染时,它都会创建嵌套/内部函数
不,内部函数/闭包非常普遍,它们没有问题。引擎可以极大地优化它们。
这里的意思是,您将函数作为道具传递给子组件。而且,由于该函数是“重新创建的”,所以它不等于传递的上一个函数,因此孩子确实会重新渲染(这对性能不利)。
您可以使用useCallback
来解决该问题,它可以记住函数引用。
答案 3 :(得分:1)
有趣的问题,我和我的同事对此有一些担心,所以我进行了测试。
我创建了1个带有Hooks的组件和1个带有Class的组件,在其中放置了一些函数,然后将其渲染1000倍。
具有类的组件如下:
export class ComponentClass extends React.PureComponent {
click1 = () => {
return console.log("just a log");
};
render() {
return (
<>
<span onClick={this.click1}>1</span>
</>
);
}
}
带有挂钩的组件看起来像这样:
export const ComponentHook = React.memo((props) => {
const click1 = () => {
return console.log("just a log");
};
return (
<>
<span onClick={click1}>1</span>
</>
);
});
我向组件添加了更多单击处理程序,然后将它们渲染了约1000倍,由于类没有定义每个渲染的函数,因此Class更快,如果增加定义的函数数量,则差异会更大:
这里是一个codeandbox,因此您可以测试Class vs Hooks的性能:https://codesandbox.io/s/hooks-vs-class-forked-erdpb
答案 4 :(得分:1)
受到@tibbus 基准测试的启发,我制作了这个测试使用或不使用 useCallback 钩子的性能。经过多次执行,可以看出 useCallback 的使用对于高频渲染非常重要。
执行 1
执行 2
执行 3
https://codesandbox.io/s/usecallback-vs-raw-definition-xke9v?file=/src/App.js
答案 5 :(得分:0)
按照React Documentation(结尾部分)
后一种语法的问题是创建了不同的回调 每次
LoggingButton
呈现时。在大多数情况下,这很好。 但是,如果将此回调作为对较低组件的支持传递, 这些组件可能会进行额外的重新渲染。我们一般 建议在构造函数中绑定或使用类字段语法, 以避免这种性能问题。
类字段语法:
class LoggingButton extends React.Component {
// This syntax ensures `this` is bound within handleClick.
// Warning: this is *experimental* syntax.
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
回调语法中的箭头函数:
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// This syntax ensures `this` is bound within handleClick
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
答案 6 :(得分:0)
老实说,在这些情况下,我只会使用类组件。我知道过早的优化,但每次创建一个新函数似乎都是一种奢侈的浪费,没有太多的可维护性优势。 tibbus 已经证明了 perf 命中,并且内联函数可以说比类方法可读性差。您失去的只是编写函数式组件的流畅感觉。