Javascript 使用useEffect时超出最大深度

Javascript 使用useEffect时超出最大深度,javascript,reactjs,Javascript,Reactjs,我正在尝试为我的产品CRUD实现一个简单的搜索算法。 我的想法是在搜索栏中输入输入,每次用户更改输入时,匹配搜索的产品都会立即出现,而无需点击搜索按钮。 然而,我试着这样做: function filterProducts (productName, productList) { const queryProducts = productList.filter((prod)=> { return prod.title === productName; }); retur

我正在尝试为我的产品CRUD实现一个简单的搜索算法。 我的想法是在搜索栏中输入输入,每次用户更改输入时,匹配搜索的产品都会立即出现,而无需点击搜索按钮。 然而,我试着这样做:

function filterProducts (productName, productList) {
  const queryProducts = productList.filter((prod)=> {
    return prod.title === productName;
  });
  return queryProducts;
}

function HomePage () {
  const [productList, setProductList] = useState([]);
  const [popupTrigger, setPopupTrigger] = useState('');
  const [productDeleteId, setProductDeleteId] = useState('');
  const [queryString, setQueryString] = useState('');
  let history = useHistory();


  useEffect(() => {
    if (queryString.trim() === "") {
      Axios.get("http://localhost:3001/api/product/get-all").then((data) => {
        setProductList(data.data);
      });
      return;
    }
    const queryProducts = filterProducts(queryString, productList);
    setProductList(queryProducts);
  }, [queryString, productList]);
我知道
productList
会更改每个渲染,这可能就是它不起作用的原因。但我不知道如何解决这个问题。我在这里看到了useReducer的其他问题和解决方案,但我觉得它们似乎都没有帮助我。 错误如下所示:


警告:超过最大更新深度。当组件在useEffect内部调用setState时,可能会发生这种情况,但useEffect没有依赖项数组,或者每个渲染中的一个依赖项都会更改。

当您在useEffect挂钩中使用setState函数,同时将该setState函数的状态作为useEffect挂钩的依赖项之一时,您将获得这种递归效果,最终无限地重新渲染组件

因此,首先我们必须从useEffect中删除productList。然后,我们可以使用一个函数来更新您的状态,而不是陈旧的更新(就像您在示例中所做的那样)


现在,您仍然可以访问过滤器的productList,但您不必将其包含在依赖项中,依赖项应负责无限重渲染。

这里要做的是获取产品列表并根据查询字符串对其进行过滤,然后使用过滤后的列表渲染UI。因此理想情况下,
filteredList
只是基于
queryString
productList
的派生状态。因此,您可以从useEffect中删除
filterProducts
,并将其移到外部。这样,当状态发生变化时,它就会运行

function filterProducts (productName = '', productList = []) {
  return productName.trim().length > 0 ? productList.filter((prod)=> {
    return prod.title === productName;
  }); : productList
}

function HomePage () {
  const [productList, setProductList] = useState([]);
  const [queryString, setQueryString] = useState('');
 


  useEffect(() => {
    if (queryString.trim() === "") {
      Axios.get("http://localhost:3001/api/product/get-all").then((data) => {
        setProductList(data.data);
      });
    }
  }, [queryString]);

  // query products is the derived state 
  const queryProducts = filterProducts(queryString, productList);

  // Now instead of using productList to render something use the queryProducts
  return (
    {queryProducts.map(() => {
      ..... 
    })}
  )
如果希望仅在
queryString
productList
中的更改时运行
filterProducts
,则可以将其包装在UseMoom中

const queryProducts = React.useMemo(() => filterProducts(queryString, productList), [queryString, productList]);

我建议对代码进行一些更改

  • 我会将始终立即反映用户输入的状态与表示发送到后端的查询的状态分开。我会在这两个州之间加上一个去盎司。大概是这样的:
  • 我将把从后端返回的原始数据和从后端派生的过滤数据分开
  • 我会将
    useffect
    拆分,而不是将不同的关注点都混合到一个中(没有规则规定不能有多个
    useffect

  • productList
    在依赖项数组中,但是在useffect中调用了
    setProductList
    。如果
    setProductList
    每次设置相同的数据,则不会出现问题。这是否回答了您的问题?谢谢你,这正是我想要的!
    const queryProducts = React.useMemo(() => filterProducts(queryString, productList), [queryString, productList]);
    
    const [query, setQuery] = useState('');
    const [userInput, setUserInput] = useState('');
    useDebounce(userInput, setQuery, 750);
    
    const [products, setProducts] = useState([]);
    const [filteredProducts, setFilteredProducts] = useState([]);
    
    useEffect(() => {
        if (query.trim() === '') {
          Axios
            .get("http://localhost:3001/api/product/get-all")
            .then((data) => { setProducts(data.data) });
        }
      }, [query]);
    
    useEffect(
        () => setFilteredProducts(filterProducts(userInput, products)),
        [userInput, products]
    );