简体   繁体   English

为什么 React 不能正确更新我的状态?

[英]Why doesn't React update my state correctly?

I am displaying my state, which is an array, by iterating through it with the map function.我通过使用 map 函数遍历它来显示我的状态,它是一个数组。 Additionally, I have a button that reverses the array on click.此外,我有一个按钮可以在单击时反转数组。

import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import "./App.css";

const App = (props) => {
  const [reverse, setReverse] = useState(false);

  const [arr, setArr] = useState([]);

  useEffect(() => {
    let newArr = props.arr;

    newArr = newArr.reverse();

    setArr(newArr);
  }, [reverse, props.arr]);

  return (
    <div className="App">
      <button
        onClick={() => {
          setReverse(!reverse);
        }}
      >
        Reverse
      </button>
      {arr.map((e, i) => {
        return (
          <div key={i}>
            <p>{e}</p>
          </div>
        );
      })}
    </div>
  );
};

App.propTypes = {
  arr: PropTypes.array,
};

export default App;

I think it is fairly obvious what I want to do.我想我想做什么是很明显的。 But it doesn't work for me and I don't know why.但这对我不起作用,我不知道为什么。 I have to click twice to accomplish the first reversion and the weird case emerges in which the array that is rendered and the one shown in the component state by the React dev tools in Chrome do not match.我必须单击两次才能完成第一次还原,并且出现了奇怪的情况,其中呈现的数组与 Chrome 中的 React 开发工具在组件状态中显示的数组不匹配。

在此处输入图片说明

I cannot explain this behaviour.我无法解释这种行为。 I am starting to think that it has something to do with the fact that I'm getting the array from the props, but I don't really know.我开始认为这与我从 props 获取数组的事实有关,但我真的不知道。 Any ideas?有任何想法吗?

There are several improvements to be made.有几项改进需要进行。 Some are bugs, and others are just anti-patterns.有些是错误,有些只是反模式。

The first thing to note is that reverse mutates the original array.首先要注意的是reverse改变原始数组。 You should never mutate state or props in React.你永远不应该在 React 中改变 state 或 props。

The second is an anti-pattern involving copying props into state that do not need to be.第二个是反模式,涉及将道具复制到不需要的状态。

The React docs say that state is for values that change over time. React 文档说状态是用于随时间变化的值。 It says that a value is not state if it can be derived from props.它说如果一个值可以从 props 派生出来,它就不是状态。

Can you compute it based on any other state or props in your component?您可以根据组件中的任何其他状态或道具来计算它吗? If so, it isn't state.如果是这样,它不是状态。

That is what we have in this case.这就是我们在这种情况下所拥有的。

Instead of copying the prop arr into state and reversing it there, we can just use the prop and a temporary variable to accomplish the same goal with less code.与其将 prop arr复制到 state 并在那里反转它,我们可以只使用 prop 和一个临时变量来用更少的代码完成相同的目标。

 const {useState, useEffect} = React; const App = (props) => { const [reverse, setReverse] = useState(false); let array = [...props.arr]; // New reference so we will not mutate props if (reverse) { array.reverse(); } return ( <div className="App"> <button onClick={() => { setReverse(!reverse); }} > Reverse </button> {array.map((e, i) => { return ( <div key={i}> <p>{e}</p> </div> ); })} </div> ); }; ReactDOM.render(<App arr={[1,2,3]} />, document.getElementById('root'));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

That's because the useEffect() hook runs on the mount of your component and reverses your array although you haven't clicked the reverse button.那是因为useEffect()钩子在您的组件安装上运行并反转您的数组,尽管您还没有单击反转按钮。

Try adding logic to avoid the first reversal that is happening on the mount.尝试添加逻辑以避免装载上发生的第一次逆转。

This would probably work for you,这可能对你有用,

  useEffect(() => {
      if(arr.length>0){
         let newArr = props.arr;
         newArr = newArr.reverse();
         setArr(newArr);
      }
  }, [reverse, props.arr]);

The main mistake is that you are assigning your props to the newArr variable, not arr , so each time it is not the new state of arr that is reversed, but the original array of props .主要错误是,你分配你的道具到newArr变量,而不是arr ,每次所以它不是新状态arr被逆转,但原来阵列props Also, when changing the props , it is better to add one more useEffect .另外,在更改props ,最好再添加一个useEffect I have provided an example of the correct code below I apologize if there are mistakes, I do not speak English well我在下面提供了正确代码的示例,如果有错误,我深表歉意,我的英语说得不好

  useEffect(() => {
    setArr(props.arr);
  }, [props.arr]);

  useEffect(() => {
    if (!arr.length) return;

    let newArr = arr.length ? [...arr] : [...props.arr];
    newArr = [...newArr.reverse()];
    setArr(newArr);
  }, [reverse]);

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

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