ReactJS 如何在循环中记忆以呈现相同的组件
ReactJS how to memoize within a loop to render the same component
我有一个使用循环创建多个组件的组件,但我只需要重新渲染正在修改的实例,而不是其余的实例。这是我的方法:
function renderName(item) {
return (
<TextField value={item.value || ''} onChange={edit(item.id)} />
);
}
function renderAllNames(items) {
const renderedItems = [];
items.forEach(x => {
const item = React.useMemo(() => renderName(x), [x]);
renderedItems.push(item);
});
return renderedItems;
};
return (
<>
{'Items'}
{renderAllNames(names)};
</>
);
这告诉我 hooks 调用比之前的渲染要多。尝试这样做:
function renderAllNames(items) {
const renderedItems = [];
items.forEach(x => {
const item = React.memo(renderName(x), (prev, next) => (prev.x === next.x));
renderedItems.push(item);
});
return renderedItems;
};
也没用...基本方法很好用
function renderAllNames(items) {
const renderedItems = [];
items.forEach(x => {
renderedItems.push(renderName(x));
});
return renderedItems;
};
但它会在我每次编辑任何字段时呈现所有动态组件,那么我如何才能记住它以便仅重新呈现正在编辑的项目?
您正在破坏 rules of hooks。 Hooks 应该只用在组件的顶层,这样 React 才能保证调用顺序。组件记忆也应该只使用 React.memo
完成,并且组件应该只在全局范围内声明,而不是在其他组件内声明。
我们可以将 renderName
变成它自己的组件,RenderName
:
function RenderName({item, edit}) {
return (
<TextField value={item.value || ''} onChange={() => edit(item.id)} />
);
}
然后这样记下来:
const MemoRenderName = React.memo(RenderName, (prev, next) => {
const idEqual = prev.item.id === next.item.id;
const valEqual = prev.item.value === next.item.value;
const editEqual = prev.edit === next.edit;
return idEqual && valEqual && editEqual;
});
React.memo
默认对所有props进行严格比较。由于 item
是一个对象,没有两个对象是严格相等的,所以必须深入比较属性。旁注:这仅在 edit
是引用稳定函数时才有效。你没有展示它,但它必须被包裹在它自己的记忆挂钩中,例如 useCallback
或者完全脱离渲染周期。
现在回到父组件你可以直接映射names
:
return (
<>
{'Items'}
{names.map(name => <MemoRenderName item={name} edit={edit}/>)}
</>
);
我有一个使用循环创建多个组件的组件,但我只需要重新渲染正在修改的实例,而不是其余的实例。这是我的方法:
function renderName(item) {
return (
<TextField value={item.value || ''} onChange={edit(item.id)} />
);
}
function renderAllNames(items) {
const renderedItems = [];
items.forEach(x => {
const item = React.useMemo(() => renderName(x), [x]);
renderedItems.push(item);
});
return renderedItems;
};
return (
<>
{'Items'}
{renderAllNames(names)};
</>
);
这告诉我 hooks 调用比之前的渲染要多。尝试这样做:
function renderAllNames(items) {
const renderedItems = [];
items.forEach(x => {
const item = React.memo(renderName(x), (prev, next) => (prev.x === next.x));
renderedItems.push(item);
});
return renderedItems;
};
也没用...基本方法很好用
function renderAllNames(items) {
const renderedItems = [];
items.forEach(x => {
renderedItems.push(renderName(x));
});
return renderedItems;
};
但它会在我每次编辑任何字段时呈现所有动态组件,那么我如何才能记住它以便仅重新呈现正在编辑的项目?
您正在破坏 rules of hooks。 Hooks 应该只用在组件的顶层,这样 React 才能保证调用顺序。组件记忆也应该只使用 React.memo
完成,并且组件应该只在全局范围内声明,而不是在其他组件内声明。
我们可以将 renderName
变成它自己的组件,RenderName
:
function RenderName({item, edit}) {
return (
<TextField value={item.value || ''} onChange={() => edit(item.id)} />
);
}
然后这样记下来:
const MemoRenderName = React.memo(RenderName, (prev, next) => {
const idEqual = prev.item.id === next.item.id;
const valEqual = prev.item.value === next.item.value;
const editEqual = prev.edit === next.edit;
return idEqual && valEqual && editEqual;
});
React.memo
默认对所有props进行严格比较。由于 item
是一个对象,没有两个对象是严格相等的,所以必须深入比较属性。旁注:这仅在 edit
是引用稳定函数时才有效。你没有展示它,但它必须被包裹在它自己的记忆挂钩中,例如 useCallback
或者完全脱离渲染周期。
现在回到父组件你可以直接映射names
:
return (
<>
{'Items'}
{names.map(name => <MemoRenderName item={name} edit={edit}/>)}
</>
);