useEffect 第二个参数无限渲染

时间:2021-02-06 19:00:01

标签: reactjs react-hooks

我在 getEmployees(url) 中调用一个函数 (useEffect),没有第二个参数。

我想在每次添加 getEmployees(url 时调用 employee)。 一旦我添加 employeeerror 作为第二个参数,useEffect 将无限重新渲染。

这是它应该如何工作吗?

import React, { useEffect, useState, useCallback } from 'react'  

//
import EmployeeRecord from './EmployeeRecord'

const Employees = () => {
    const [loading, setLoading] = useState(false);
    const [employees, setEmployees] = useState([]);
    const [error, setError] = useState({show: false, msg: ''});
    
    // 
    const url = 'http://localhost:3001/';


    //
    // const fetchDrinks = useCallback( async () => {
    const getEmployees = useCallback( async (url) => {
        setLoading(true)
        try {
          const response = await fetch(url)
          const data = await response.json() 

          if (data) {
            setEmployees(data)  
            setError({ show: false, msg: '' })
          } else {
            setError({ show: true, msg: data.Error })
          }
          setLoading(false)
        } catch (error) {
          console.log(error)
        }
      }, []);
    
      useEffect(() => {
        getEmployees(url) 
      }, [])
      
      console.log("11111111 from employee.js ")

      if (loading){
        return (
            <div>
                .....is loading 
            </div>
        )
      }
    return (
        <div>
            <div className="addinfo-infomations">
                <EmployeeRecord employees={employees}/>
            </div>
        </div>
    )
}

export default Employees

3 个答案:

答案 0 :(得分:0)

useEffect 的第二个参数是一个依赖项列表,告诉 React 在任何依赖项发生变化时再次调用您的 useEffect 函数。

如果没有依赖项([]),它会在组件挂载时运行。

现在,如果您将 employees 作为依赖项,则每次设置 employees 数组时它都会更改。而且,您可以看到在您的 getEmployees 函数中,您调用了 setEmployees。这就是你最终进入循环的方式:

useEffect -> getEmployees -> setEmployees -> (employees changes, triggering useEffect again)

为了避免这种情况,您必须不形成回路,或以某种方式将其短路。

您说每次添加员工时都想运行 getEmployees,但是您所展示的代码中没有处理添加员工的代码。所以,我假设这可能发生在您正在轮询的服务器上?如果是这样,您将需要找到某种方法从服务器获取通知——这不仅仅是调用 useEffect 的问题,因为 React 将无法知道添加了一名员工.或者,您的示例缺少一些相关代码。

答案 1 :(得分:0)

调用 getEmployees 会导致 employeeserror 发生变化。如果您添加员工或错误作为第二个参数,则意味着 useEffect 将在 employeeserror 更改时执行其回调。因此,当您调用 getEmployees 时,useEffect 将执行其回调。然后 useEffect 的回调会调用 getEmployees。无穷大发生了。

我想如果你想重新加载员工,你可以添加一个刷新按钮

const [refresh, setRefresh] = React.useState(true);
const doRefresh = React.useCallback(() => {
    setRefresh(pre => !pre);
}, []);

useEffect(() => {
   ...
}, [refresh]);

return (
   <div>
      ...
      <button onClick={doRefresh}>reload</button>
   </div>
)

或自动重新加载

useEffect(() => {
   let handle;
   const task = () => {
       getEmpolyees().then(() => {
           handle = setTimeout(task, 1000)
       });
   }
   task();
   return () => {
      handle && clearTimeout(handle);
   }
}, [])

答案 2 :(得分:0)

我觉得添加的员工与您从 fetch 返回的数据应该不同,如果他们不同,您需要将它们分开,以便按照您现在的方式工作.为它添加另一个状态就足够了,假设我们将其命名为 setData,因为您将其命名为 data。您现在可以使用 setData 而不是员工,这样效果不会启动无限循环,然后使用其所有依赖项更新效果,您就没有问题了。

const Employees = () => {
  const [loading, setLoading] = useState(false);
  const [employees, setEmployees] = useState([]);
  const [data, setData] = useState();
  const [error, setError] = useState({ show: false, msg: '' });

  //
  const url = 'http://localhost:3001/';

  //
  // const fetchDrinks = useCallback( async () => {
  const getEmployees = useCallback(async url => {
    setLoading(true);
    try {
      const response = await fetch(url);
      const data = await response.json();

      if (data) {
        setData(data)  
        setError({ show: false, msg: '' })
      } else {
        setError({ show: true, msg: data.Error });
      }
      setLoading(false);
    } catch (error) {
      console.log(error);
    }
  }, []);

  useEffect(() => {
    url && getEmployees(url);
  }, [url, employees, getEmployees]);

  if (loading) {
    return <div>.....is loading</div>;
  }
  return (
    <div>
      <div className="addinfo-infomations">
        <EmployeeRecord employees={employees} data={data} />
      </div>
    </div>
  );
};