React在更新作为道具传递的状态var后不重新呈现子组件



我正在写一个简单的"像素艺术";绘画程序,只是为了好玩。我已经让绘画部分工作,但我想有一个按钮,重置";像素";我想我一定对React渲染的工作原理有一些误解。

我在下面包含了我正在使用的代码的简化版本。以下是当你点击红色单元格并";"油漆";它变成粉红色,然后点击重置按钮:

  1. 网格组件的resetPaint状态变量从false更改为true
  2. 这将导致在resetPaint设置为true的情况下重新渲染"栅格">
  3. 由于resetPaint被传递给了Cell,Cell的道具现在已经改变了,所以它重新渲染(或者至少在VDOM中有所不同?(
  4. Cell中的if (resetPaint)...逻辑使其恢复为默认颜色,从而使其在DOM中重新呈现
  5. 在Cell渲染后,我们用resetPaint && setResetPaint(false)重置resetPaint

看看console.log语句,看起来发生的事情更像这样:

  1. 网格组件的resetPaint状态变量从false更改为true
  2. 这将导致在resetPaint设置为true的情况下重新渲染网格
  3. 单元格不进行重新渲染
  4. 我们用resetPaint && setResetPaint(false)重置resetPaint
  5. 网格再次渲染,这次resetPaint设置为false
  6. 现在Cell重新渲染,但由于resetPaint为false,因此颜色不会更改

我认为第二次网格渲染是由setResetPaint(false)引起的,虽然如果可以避免这种情况会很好,因为我知道它不会(或不应该(改变任何事情,但我很困惑为什么"细胞"在resetPaint设置为true后不重新渲染,而在设置为false后重新渲染。

我希望这意味着我即将探索React的某些方面,而我显然还没有探索;有人能帮我到那里吗?

您还可以查看并处理此沙盒中的代码(UPDATED使用工作代码(请参阅答案((。

import React from 'react';
export const Cell = ({  defaultColor, selectedColorRef, resetPaint}) => {
const [color, setColor] = React.useState(defaultColor)
const onClick = () => setColor(selectedColorRef.current);
React.useEffect(() => {
if (resetPaint) {
setColor(defaultColor);
}
}, [resetPaint]);
console.log(`Cell rendering with resetPaint=${resetPaint} and color=${color} (${defaultColor})`); 
return <div {...{ style: {backgroundColor: color, width:'50px', height:'50px'}, onClick }} />
}
export const Grid = () => {
// Denotes the selected color in the color palette (palette omitted here for simplicity)
const selectedColorRef = React.useRef('pink'); 
// Supposed to trigger a re-render with original color
const [resetPaint, setResetPaint] = React.useState(false);

console.log(`Grid rendering with resetPaint=${resetPaint}`);
const grid = (
<div>
{/* 
Normally the drawing "canvas" would be a grid of Cells like this, 
but we'll just include one for simplicity. 
*/}
<Cell {...{defaultColor: "red", selectedColorRef, resetPaint}} />
<button onClick={() => setResetPaint(true)}>Reset</button>
</div>
)
useEffect(() => {
resetPaint && setResetPaint(false);
}, [resetPaint]);
return grid;
}

如果孩子的props是从父母那里得到的,你应该在useEffect中设置统计数据,如果你做了一些类似于吹的事情,它在道具更改后不会更新

export default const Child(props) {
const [state, setState ] = useState(props.state);

}

这不起作用,所以你应该使用结构吹

export default const Child(props) {
const [state, setState ] = useState(null);
useEffect(() => {
setState(props.state);
}, [props]);
}

找到了答案!在单元格有时间完成渲染之前,父级中的resetPaint值被重新设置。把它移到一个有用的地方。这样的效果解决了问题。

useEffect(() => {
resetPaint && setResetPaint(false);
}, [resetPaint]);

我已经更新了代码沙盒来反映这一点。

最新更新