首页 > 解决方案 > 状态变化未反映在 Next.Js 中的功能中

问题描述

我有一个渲染出一系列产品的功能组件。我从它的道具中得到了一系列产品,并设置了它的状态使用useEffectuseState钩子。

我正在尝试通过获取原始数组并根据某些条件对其进行过滤来实现一个简单的搜索过滤器功能。

该组件会重新渲染几次,因为它是从父级中的 ajax 调用加载的项目。这里的问题是,即使originalItems最终更新了 的值,也不会反映handleFiltering调用该方法的时间。在这个方法中, 的值originalItems仍然是一个空数组。

有人可以解释为什么这个变量的状态没有在这个函数中更新吗?有没有办法解决这个问题?提前致谢!

这是代码:

const ProductList = ({ items }) => {
  const [taggedWith, setTaggedWith] = useState("");
  const [queryValue, setQueryValue] = useState("");
  const [originalItems, setOriginalItems] = useState([]);
  const [filteredItems, setFilteredItems] = useState([]);

  useEffect(() => {
    setOriginalItems(items);
    setFilteredItems(items);
  }, [items]);
  
  const handleQueryValueChange = useCallback(
    (value) => {
      setQueryValue(value);
      handleFiltering(value, taggedWith);
    },
    [taggedWith, handleFiltering]
  );
  const handleTaggedWithChange = useCallback(
    (value) => {
      setTaggedWith(value);
      handleFiltering(queryValue, value);
    },
    [queryValue, handleFiltering]
  );

// PROBLEM HERE
  const handleFiltering = useCallback(
    (filter, tag) => {
      // originalItems is still an empty array here. So as a result, the filteredValues 
      array is always empty. 
      const filtered = originalItems.filter((item) => {
        if ((!filter || item.title.toLowerCase().includes(filter.toLowerCase())) && (!tag || 
        item.tags.includes(tag))) return item;
      });
      setFilteredItems(filtered);
    },
    [originalItems]
  );

  return (
    <Page >
      <Card>
        <ResourceList
          items={filteredItems}
          loading={loading}
        />
      </Card>
    </Page>
  );
};


export default ProductList;

(请注意,我省略了一些代码以减少混乱。taggedWith和的值queryValue已正确更新,但我省略了那段代码)

标签: javascriptreactjsreact-hooksnext.jsuse-state

解决方案


我怀疑你过度使用useCallback. 在某些有限的情况下,在非常昂贵的情况下运行回调时,进行记忆化回调可能会有所帮助。但是您必须非常小心以确保您的依赖项列表是正确的。

在您的实例中,没有理由记住handleQueryValueChangeand handleTaggedWithChange,这些可能会导致您的问题。它们既没有依赖itemsoriginalItems没有依赖,因此它们没有得到更新。

真正重要的部分是过度使用 memoization 意味着这些函数引用了旧的副本handleFiltering,该副本存在于originalItems仍然是空数组的范围/上下文中。

摆脱所有useCallbacks 可能是最好的方法......handleFiltering如果您开始遇到性能问题并且发现 memoization 有帮助,您可以随时将其添加回来。


推荐阅读