我正在写一个简单的"像素艺术";绘画程序,只是为了好玩。我已经让绘画部分工作,但我想有一个按钮,重置";像素";我想我一定对React渲染的工作原理有一些误解。
我在下面包含了我正在使用的代码的简化版本。以下是当你点击红色单元格并";"油漆";它变成粉红色,然后点击重置按钮:
- 网格组件的
resetPaint
状态变量从false
更改为true
- 这将导致在
resetPaint
设置为true
的情况下重新渲染"栅格"> - 由于
resetPaint
被传递给了Cell,Cell的道具现在已经改变了,所以它重新渲染(或者至少在VDOM中有所不同?( - Cell中的
if (resetPaint)...
逻辑使其恢复为默认颜色,从而使其在DOM中重新呈现 - 在Cell渲染后,我们用
resetPaint && setResetPaint(false)
重置resetPaint
看看console.log
语句,看起来发生的事情更像这样:
- 网格组件的
resetPaint
状态变量从false
更改为true
- 这将导致在
resetPaint
设置为true
的情况下重新渲染网格 - 单元格不进行重新渲染
- 我们用
resetPaint && setResetPaint(false)
重置resetPaint - 网格再次渲染,这次
resetPaint
设置为false
- 现在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]);
我已经更新了代码沙盒来反映这一点。