簡體   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