【发布时间】:2020-12-03 23:17:56
【问题描述】:
我正在渲染视频中的一系列帧,每个帧都在自己的组件中。帧作为状态存储在名为 Timeline 的父组件中。
由于我需要从子组件中操作帧数组的元素,因此我传入了索引为 i 的回调函数,并带有一个闭包。为了避免单个帧的变化影响所有帧,我在每个Frame 周围使用了memo 高阶组件。
尽管如此,我发现每次选择帧时,都会重新渲染所有帧。使用 whyDidyouUpdate 钩子 (https://usehooks.com/useWhyDidYouUpdate/),我将其归结为我的回调在每次渲染时都会发生变化。
我尝试做onClick={useCallback(() => selectFrame(i), [])},但框架根本没有改变颜色,这表明这在某种程度上阻碍了回调正常运行。
let Frame = memo(({frame, ...}) => (
<img style={{border: frame.selected ? "green" : "red";}} />
);
let Timeline = () => {
let [frames, setFrames] = useState([
{ id: "00000", selected: True, ...more image information },
{ id: "00001", selected: True, ...more image information },
{ id: "00002", selected: True, ...more image information },
]);
let selectFrame = (i) => {
let newFrames = [...frames];
newFrames[i].mask = base64;
setFrames(newFrames);
}
return (
<div>
{frames.map((f, i) => (
<Frame
frame={f}
key={f.id}
onClick={() => selectFrame(i)}
/>
)}
</div>
));
}
对处理此问题的正确方法有什么建议吗?谢谢
编辑:Drew 下面的解决方案为我指明了正确的方向。正确的语法是:
const selectFrame = (i) => useCallback(() =>
setFrames(frames.map((f, j) => (
(i === j) ? {...f, selected: !f.selected} : f
))), []);
您需要为每个函数设置不同的记忆回调。
【问题讨论】:
-
我倾向于这只是适当的 React 行为。您正在传递一个回调,当它触发时,它会导致它被传递到的组件中重新呈现。如果您想完全避免这种情况,您可能只需要通过回调最常见的祖先/父级来提升您正在操作的状态/行为
-
如果它是一个共享的有状态行为(不是上下文的),它可能会成为一个自定义 Hook...
标签: javascript reactjs react-hooks