在反应中,我确实经常需要使用诸如 useCallback 之类的内容来记忆项目列表中的函数(通过循环创建),以避免由于引用标识符不匹配而导致单个元素发生更改而重新渲染所有组件……不幸的是,这是令人惊讶的是很难到期。例如,考虑以下代码:
const MyComp = memo({elements} => {
{
elements.map((elt, i) => {
<>{elt.text}
其中 Button 是由 ant design 等提供的外部组件。然后,这个函数引用在每次渲染时都会不同,因为它是内联的,因此强制重新渲染。
为了避免这个问题,我可以想到另一种解决方案:创建一个新组件 MyButton,它接受两个属性 index={i} 和 onClick 而不是单个 onClick,并将参数 index 附加到任何调用onClick:
const MyButton = ({myOnClick, id, ...props}) => {
const myOnClickUnwrap = useCallback(e => myOnClick(e, id), [myOnClick]);
return
};
const MyComp = memo({elements} => {
const myOnClick = useCallback((e, id) => dispatch(removeElement({id: id})), []);
return
{
elements.map((elt, i) => {
<>{elt.text}
虽然这确实有效,但由于多种原因,这是非常不实用的:
Button 等外部库中的所有元素,并重写原本不打算处理这种嵌套的组件……这会破坏模块化并使代码更加复杂,这意味着我需要完全通用地创建一个更复杂的版本 MyButton 来检查嵌套级别的数量。我无法使用 index={[index1,index2,index3]},因为这是一个数组,因此没有稳定的引用。indexes 的命名没有约定,这意味着项目之间共享代码或开发库更加困难我缺少更好的解决方案吗?考虑到列表无处不在,我不敢相信对此没有适当的解决方案,而且我很惊讶地看到这方面的文档很少。
编辑 我尝试这样做:
// Define once:
export const WrapperOnChange = memo(({onChange, index, Component, ...props}) => {
const onChangeWrapped = useCallback(e => onChange(e, index), [onChange, index]);
return
});
export const WrapperOnClick = memo(({onClick, index, Component, ...props}) => {
const onClickWrapped = useCallback(e => onClick(e, index), [onClick, index]);
return
});
并像这样使用它:
const myactionIndexed = useCallback((e, i) => dispatch(removeSolverConstraint({id: i})), []);
return
但这仍然不完美,特别是我需要一个用于不同嵌套级别的包装器,每当我定位一个新属性时我都需要创建一个新版本(onClick,onChange,...),如果我有它就无法直接工作多个属性(例如 onClick 和 onChange),我以前从未见过这个,所以我想有更好的解决方案。
编辑 我尝试了各种想法,包括使用 fast-memoize,但我仍然不明白所有结果:有时,fast-memoize 有效,有时失败......而且我不知道 fast-memoize 是否是推荐的解决方案:似乎对于如此常见的用例使用第三方工具很奇怪。在这里查看我的测试https://codesandbox.io/embed/magical-dawn-67mgxp?fontsize=14&hidenavigation=1&theme=dark
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号