繁体   English   中英

更改数组中的一个状态会导致在 React Hooks 中重新渲染整个循环生成的自定义组件

[英]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来跟踪状态的当前值。 这允许我们指定[]作为依赖项

编辑 Peace-pine-wmxwy

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM