React Hooks - 如何实现 shouldComponentUpdate?
React Hooks - How do I implement shouldComponentUpdate?
我知道你可以通过传递一个数组作为可选的第二个参数来告诉 React 跳过一个 effect。
例如:
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes
但是如果我想控制比较呢?添加我自己的比较逻辑。
我希望您可以像 React.memo
那样将函数作为第二个参数传递。
如果传入数组的 属性 发生变化,则传递可选的第二个数组参数会启动效果函数 - 就像 class 组件中的 shouldComponentUpdate
方法 运行 当传递给组件的道具发生变化时。您可以根据参数的值在效果函数中决定是否要应用效果。
这是一个自定义挂钩,它接受一个更新函数,returns一个只有当更新函数returns为真时才会改变的值,可以在第二个参数中传递给[=13] =] 或 useCallback
或 useMemo
强制 re-render:
function useShouldRecalculate(shouldRecalculateFn) {
const prevValueRef = useRef(0);
if(shouldRecalculateFn()) {
// If we need to recalculate, change the value we return
prevValueRef.current += 1;
} // else we return the same value as the previous render, which won't trigger a recalculation
return prevValueRef.current;
}
例如,这将仅在计数为偶数时更新文档标题:
const shouldUpdateTitle = useShouldRecalculate(
() => count % 2 === 0
);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [shouldUpdateTitle]); // eslint-disable-line react-hooks/exhaustive-deps
为什么你可能不应该这样做
在大多数情况下,我不建议这样做。
一般来说,使用惯用的挂钩 API 将有更简洁的方法来完成相同的任务。 (上面的示例可能只是在更新文档标题的行周围放置了一个 if
块。)
也许更重要的是,deps
论点不仅仅是关于优化,而是关于保持闭包值 up-to-date,并避免像这样的错误:
const [count, setCount] = useState(0)
const increment = useCallback(() => {
// Bug: `count` is always 0 here, due to incorrect use of the `deps` argument
setCount(count + 1)
}, [])
此错误将被 react-hooks/exhaustive-deps
linter 规则捕获,但您必须在使用自定义逻辑控制执行的任何地方禁用该规则。
使用自定义记忆化逻辑可能会使您的组件更 bug-prone 并且通常更难推理。所以我认为这个 useShouldRecalculate
挂钩是最后的手段。
在上面的评论中 Gabriele Petrioli 链接到解释如何实施 shouldComponentUpdate 的 React.memo 文档。我在谷歌上搜索了 shouldComponentUpdate + useEffect + "react hooks" 的组合,结果是这个。因此,在使用链接文档解决了我的问题后,我想我也应该将这些信息带到这里。
这是实现 shouldComponentUpdate 的旧方法:
class MyComponent extends React.Component{
shouldComponentUpdate(nextProps){
return nextProps.value !== this.props.value;
}
render(){
return (
<div>{"My Component " + this.props.value}</div>
);
}
}
新的 React Hooks 方式:
React.memo(function MyComponent (props) {
return <div>{ "My Component " + props.value }</div>;
})
我知道您可能在问题中提出了更多要求,但是对于来自 Google 的任何正在寻找如何使用 React Hooks 实施 shouldComponentUpdate 的人来说,您就可以了。
另一种方法可能是使用 useRef 来保存数据,而仅使用 useState 来存储要显示的数据。
有时这比备忘录方法更有效:我最近有一个案例,当使用 React.memo 时,React 仍在不必要地渲染,并且它弄乱了一些 PIXI 显示。
下面的方法为我修复了它......希望我没有做反模式:-)
const countRef = useRef(0);
const [countDisplay, setCountDisplay] = useState(0);
yourUpdateFunction = () => {
// This is where count gets updated
countRef.current = countRef.current + 1;
if ((countRef.current % 2) === 0) setCountDisplay(countRef.current);
}
return (<p>countDisplay</p>);
添加到 PAT-O-MATION 的回答中,
React.memo 还接受第二个参数,这是一个函数,可以用来确定一个组件是否
应该渲染还是不渲染。
如果函数 return 为真,则组件不会在更改该道具时重新渲染,相反,当 return 值为假时它会更新
function SomeComp({prop1, prop2}) {
return(
..
)
}
React.memo(SomeComp, (props, nextProps)=> {
if(props.prop1 === nextProps.prop1) {
// don't re-render/update
return true
}
})
注意:只有当回调函数return为false时组件才会重新渲染,所以在上面的例子中即使prop2值改变它也不会重新渲染
除了 Avinash 的 回答。
返回值的重要说明:
shouldComponentUpdate() {
// returns true by default
// return false if you don't need re-render
}
export default React.memo(Component, (props, nextProps) => {
if(props.prop1 === nextProps.prop1) {
// return true if you don't need re-render
}
})
我知道你可以通过传递一个数组作为可选的第二个参数来告诉 React 跳过一个 effect。
例如:
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes
但是如果我想控制比较呢?添加我自己的比较逻辑。
我希望您可以像 React.memo
那样将函数作为第二个参数传递。
如果传入数组的 属性 发生变化,则传递可选的第二个数组参数会启动效果函数 - 就像 class 组件中的 shouldComponentUpdate
方法 运行 当传递给组件的道具发生变化时。您可以根据参数的值在效果函数中决定是否要应用效果。
这是一个自定义挂钩,它接受一个更新函数,returns一个只有当更新函数returns为真时才会改变的值,可以在第二个参数中传递给[=13] =] 或 useCallback
或 useMemo
强制 re-render:
function useShouldRecalculate(shouldRecalculateFn) {
const prevValueRef = useRef(0);
if(shouldRecalculateFn()) {
// If we need to recalculate, change the value we return
prevValueRef.current += 1;
} // else we return the same value as the previous render, which won't trigger a recalculation
return prevValueRef.current;
}
例如,这将仅在计数为偶数时更新文档标题:
const shouldUpdateTitle = useShouldRecalculate(
() => count % 2 === 0
);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [shouldUpdateTitle]); // eslint-disable-line react-hooks/exhaustive-deps
为什么你可能不应该这样做
在大多数情况下,我不建议这样做。
一般来说,使用惯用的挂钩 API 将有更简洁的方法来完成相同的任务。 (上面的示例可能只是在更新文档标题的行周围放置了一个 if
块。)
也许更重要的是,deps
论点不仅仅是关于优化,而是关于保持闭包值 up-to-date,并避免像这样的错误:
const [count, setCount] = useState(0)
const increment = useCallback(() => {
// Bug: `count` is always 0 here, due to incorrect use of the `deps` argument
setCount(count + 1)
}, [])
此错误将被 react-hooks/exhaustive-deps
linter 规则捕获,但您必须在使用自定义逻辑控制执行的任何地方禁用该规则。
使用自定义记忆化逻辑可能会使您的组件更 bug-prone 并且通常更难推理。所以我认为这个 useShouldRecalculate
挂钩是最后的手段。
在上面的评论中 Gabriele Petrioli 链接到解释如何实施 shouldComponentUpdate 的 React.memo 文档。我在谷歌上搜索了 shouldComponentUpdate + useEffect + "react hooks" 的组合,结果是这个。因此,在使用链接文档解决了我的问题后,我想我也应该将这些信息带到这里。
这是实现 shouldComponentUpdate 的旧方法:
class MyComponent extends React.Component{
shouldComponentUpdate(nextProps){
return nextProps.value !== this.props.value;
}
render(){
return (
<div>{"My Component " + this.props.value}</div>
);
}
}
新的 React Hooks 方式:
React.memo(function MyComponent (props) {
return <div>{ "My Component " + props.value }</div>;
})
我知道您可能在问题中提出了更多要求,但是对于来自 Google 的任何正在寻找如何使用 React Hooks 实施 shouldComponentUpdate 的人来说,您就可以了。
另一种方法可能是使用 useRef 来保存数据,而仅使用 useState 来存储要显示的数据。 有时这比备忘录方法更有效:我最近有一个案例,当使用 React.memo 时,React 仍在不必要地渲染,并且它弄乱了一些 PIXI 显示。 下面的方法为我修复了它......希望我没有做反模式:-)
const countRef = useRef(0);
const [countDisplay, setCountDisplay] = useState(0);
yourUpdateFunction = () => {
// This is where count gets updated
countRef.current = countRef.current + 1;
if ((countRef.current % 2) === 0) setCountDisplay(countRef.current);
}
return (<p>countDisplay</p>);
添加到 PAT-O-MATION 的回答中,
React.memo 还接受第二个参数,这是一个函数,可以用来确定一个组件是否
应该渲染还是不渲染。
如果函数 return 为真,则组件不会在更改该道具时重新渲染,相反,当 return 值为假时它会更新
function SomeComp({prop1, prop2}) {
return(
..
)
}
React.memo(SomeComp, (props, nextProps)=> {
if(props.prop1 === nextProps.prop1) {
// don't re-render/update
return true
}
})
注意:只有当回调函数return为false时组件才会重新渲染,所以在上面的例子中即使prop2值改变它也不会重新渲染
除了 Avinash 的 回答。 返回值的重要说明:
shouldComponentUpdate() {
// returns true by default
// return false if you don't need re-render
}
export default React.memo(Component, (props, nextProps) => {
if(props.prop1 === nextProps.prop1) {
// return true if you don't need re-render
}
})