![](/img/trans.png)
[英]React redux - parent state changing, but child components not re-rendering
[英]Changing one state in an array causes a re-rendering of the entire loop-generated custom components in React Hooks
我正在使用 React Hooks。 我正在从地图填充按钮列表。 每个按钮在disabled
属性上都有自己的状态。 在填充它们之后,当单击一个按钮时,我想将该按钮设置为禁用。
const initialBtnDisabled = [false, false, false, false, false, false, false, false];
const [btnDisabled, setBtnDisabled] = useState(initialBtnDisabled);
const onChange = event => {
const btnIndex = event.target.value;
let btnDisabledcopy = [...btnDisabled]
btnDisabledcopy[btnIndex] = true
setBtnDisabled(btnDisabledcopy)
}
const Button = (props) => {
console.log("I am from button");
const { btnIndex } = props
return (
<button onClick={onChange} value={btnIndex} disabled={btnDisabled[btnIndex]}>click me</button>
)
}
const btnArr = [1, 2, 3, 4, 5, 6, 7, 8]
const btnFields = btnArr.map((item, index) =>
<td key={index}>
<Button btnIndex={index} />
</td>
);
return (
<tr>{btnFields}</tr>
)
现在这可行,但问题在于每次单击按钮时,Button 组件将再次为整个循环重新渲染,而我只更改了数组的一个状态。 我在Button
组件中的console.log
每次点击都会记录 8 次。
我如何防止这种情况?
您可以使用 React PureComponent 防止重新渲染。 如果传递的道具被更新,这只会重新渲染组件。
const initialBtnDisabled = [false, false, false, false, false, false, false, false];
const [btnDisabled, setBtnDisabled] = useState(initialBtnDisabled);
const onChange = event => {
const btnIndex = event.target.value;
let btnDisabledcopy = [...btnDisabled]
btnDisabledcopy[btnIndex] = true
setBtnDisabled(btnDisabledcopy)
}
class Button extends React.PureComponent {
render () {
console.log("I am from button");
const { btnIndex } = this.props;
return (
<button onClick={onChange} value={btnIndex} disabled={btnDisabled[btnIndex]}>click me</button>
)
}
}
const btnArr = [1, 2, 3, 4, 5, 6, 7, 8]
const btnFields = btnArr.map((item, index) =>
<td key={index}>
<Button btnIndex={index} />
</td>
);
return (
<tr>{btnFields}</tr>
)
您的按钮正在重新渲染,因为它们的道具正在发生变化。
通过将Button
定义移到渲染函数之外,您可以像这样实现:
const Button = memo(props => { console.log('I am from button') const { btnIndex, onClick, disabled } = props return ( <button onClick={() => onClick(btnIndex)} value={btnIndex} disabled={disabled} > click me </button> ) }) function App() { const initialBtnDisabled = [ false, false, false, false, false, false, false, false, ] const [btnDisabled, setBtnDisabled] = useState(initialBtnDisabled) const btnDisabledRef = useRef(btnDisabled) btnDisabledRef.current = btnDisabled const onClick = useCallback(btnIndex => { let btnDisabledcopy = [...btnDisabledRef.current] btnDisabledcopy[btnIndex] = true setBtnDisabled(btnDisabledcopy) }, []) const btnArr = [1, 2, 3, 4, 5, 6, 7, 8] const btnFields = btnArr.map((item, index) => ( <td key={index}> <Button btnIndex={index} onClick={onClick} disabled={btnDisabled[index]} /> </td> )) return <tr>{btnFields}</tr> } const rootElement = document.getElementById('root') ReactDOM.render(<App />, rootElement)
注意使用useRef
来跟踪状态的当前值。 这允许我们指定[]
作为依赖项
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.