使用useEffect渲染的钩子比上一次渲染期间要多

时间:2020-09-19 18:53:17

标签: reactjs react-hooks

我有一个带有对象数组的组件,除其他外,我正在基于字符串进行过滤。 问题是,当我尝试将此过滤器的返回值设置为本地状态时,会抛出我不太了解原因的错误。

import React, { useState, useEffect } from 'react';
import { useQuery } from '@apollo/react-hooks';
import gql from 'graphql-tag'
const ProductsGrid = () => {


const [productsList, setProductsList] = useState([]);
  const { loading, data } = useQuery(GET_PRODUCTS);
  if (loading) return <div><h4>bla bla bla</h4></div>
  const { merchants } = data;
  let filtered = [];
  merchants.map(merchant => {
    merchant.products.map(product => {
      if (product.name.includes('Polo')) {
        filtered.push(product);
      }
    })
  })
  console.log({ filtered });
}

这将打印以下内容:enter image description here

因此,由于我希望此数组保持我的状态,所以我决定这样做:setProductsList(filtered); 插入此行之后发生的事情是这样的:

enter image description here

它开始渲染多次。我以为每次状态改变时,它都会重新渲染该组件(如果我错了,请纠正我)。我不知道为什么要这么做多次。

因此,我考虑过使用useEffect在这里实现预期的行为。

useEffect(() => {
console.log('useeffect', data);
if (data) {
  const { merchants } = data;
  console.log({merchants })
  let filtered = [];
  merchants.map(merchant => {
    merchant.products.map(product => {
      if (product.name.includes('Polo')) {
        filtered.push(product);
        // console.log({ filtered });
      }
    })
  })
  console.log({ filtered });
  setProductsList(filtered);
}

},[数据])

输出为:enter image description here

所以,我正在了解这里发生的情况以及最近的错误是什么。 我假设我的方法是朝正确的方向进行,使用useEffect仅运行一次函数。

1 个答案:

答案 0 :(得分:0)

您的问题是由于在useEffect条件之后发生了if (loading)调用,该调用返回得早。

在条件返回语句之后调用钩子是非法的,因为它违反了始终在每个渲染器上以完全相同的顺序调用钩子的保证。

const { loading, data } = useQuery(GET_PRODUCTS);
const [productsList, setProductsList] = useState([]);
if (loading)
  return (
    <div>
      <h4>bla bla bla</h4>
    </div>
  );  // <-- Cannot use hooks after this point
useEffect(/* ... */)

要解决此问题,请将useEffect调用移到条件调用之前。