首页 > 解决方案 > 尽管我使用的是 prevState,但 SetTimeout 会改变我的状态

问题描述

尽管我使用的是 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

标签: reactjssearchsettimeoutimmutability

解决方案


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

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>
      ))}
    </>
  );
}


推荐阅读