【问题标题】:SetTimeout mutates my state despite I am using prevState尽管我使用的是 prevState,但 SetTimeout 会改变我的状态
【发布时间】:2021-06-13 12:07:36
【问题描述】:

尽管我使用的是 prevState,但 SetTimeout 会改变我的状态。第一个搜索功能起作用并过滤掉数组。 setData 完全过滤和更改数据数组。如果您键入内容、搜索并删除输入,则无法看到返回的数据。

export default function App() {
  const [data, setData] = useState([]);
  const [inputValue, setInputValue] = useState("");
  const [isLoading, setIsLoading] = useState();

  // sets inputValue state for each keystroke
  const inputValueChangeHandler = (event) => {
    setInputValue(event.target.value);
  };

  useEffect(() => {
    setIsLoading(true);

    // creates timer for filtering data
    const timer = setTimeout(() => {
      setData((prevState) => {
        // sets filter object after one second in order to filter results
        const filteredData = prevState
          // filters data according to filter value
          .filter((item, index) => {
            // return array of object values and drill down the array
            const flattenedItem = Object.values(item).map((itemLevel2) => {
              // if typeof the itemLevel2 is object (address, company), convert it to array else return the string
              if (typeof itemLevel2 === "object") {
                return Object.values(itemLevel2).map((itemLevel3) => {
                  // if typeof the itemLevel3 is object (geo), convert it to an array else return the string
                  if (typeof itemLevel3 === "object") {
                    return Object.values(itemLevel3);
                  } else {
                    return itemLevel3;
                  }
                });
              } else {
                return itemLevel2;
              }
            });

            return flattenedItem
              .flat(2) // creates a new array with all sub-array elements concatenated into it recursively up to the specified depth (2).
              .join(" ") // converts array to string
              .toLowerCase()
              .includes(inputValue.toLowerCase()); // searches if string includes filterValue
          });
        return filteredData;
      });

      setIsLoading(false);
    }, 1000);

    // clear timer while unmounting
    return () => clearTimeout(timer);
  }, [inputValue]);

  return (
    <StyledApp>
      {data.map((item) => (
        <Card key={item.id}>
          <pre>{JSON.stringify(item, null, 2)}</pre>
        </Card>
      ))}
    </StyledApp>
  );
}

工作示例:https://codesandbox.io/s/search-component-z33wc

【问题讨论】:

  • 问题不在于mutating,问题在于一旦您过滤并将data 设置为过滤后的值,您就不再拥有data 中的其他对象,因此当您删除filter 是没有办法回来的,解决办法是把原始数据单独保存在一块状态,每次需要过滤的时候都使用原始数据。

标签: reactjs search settimeout immutability


【解决方案1】:

添加另一个状态并在其中存储数据并对其进行过滤解决了问题。

export default function App() {
  const [data, setData] = useState([]);
  const [filteredData, setFilteredData] = useState([]);
  const [inputValue, setInputValue] = useState("");
  const [isLoading, setIsLoading] = useState();

  
  // sets inputValue state for each keystroke
  const inputValueChangeHandler = (event) => {
    setInputValue(event.target.value);
  };

  useEffect(() => {
    setIsLoading(true);

    // creates timer for filtering data
    const timer = setTimeout(() => {
      setFilteredData((prevState) => {
        // sets filter object after one second in order to filter results
        const filteredData = [...data]
          // filters data according to filter value
          .filter((item, index) => {
            // return array of object values and drill down the array
            const flattenedItem = Object.values(item).map((itemLevel2) => {
              // if typeof the itemLevel2 is object (address, company), convert it to array else return the string
              if (typeof itemLevel2 === "object") {
                return Object.values(itemLevel2).map((itemLevel3) => {
                  // if typeof the itemLevel3 is object (geo), convert it to an array else return the string
                  if (typeof itemLevel3 === "object") {
                    return Object.values(itemLevel3);
                  } else {
                    return itemLevel3;
                  }
                });
              } else {
                return itemLevel2;
              }
            });

            return flattenedItem
              .flat(2) // creates a new array with all sub-array elements concatenated into it recursively up to the specified depth (2).
              .join(" ") // converts array to string
              .toLowerCase()
              .includes(inputValue.toLowerCase()); // searches if string includes filterValue
          });
        return filteredData;
      });

      setIsLoading(false);
    }, 1000);

    // clear timer while unmounting
    return () => clearTimeout(timer);
  }, [inputValue, data]);

  return (
    <>
      {filteredData.map((item) => (
        <Card key={item.id}>
          <pre>{JSON.stringify(item, null, 2)}</pre>
        </Card>
      ))}
    </>
  );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    • 2019-03-12
    • 1970-01-01
    • 2019-01-16
    相关资源
    最近更新 更多