Эффект использования второго аргумента бесконечный рендеринг

#reactjs #react-hooks

#reactjs #реагирующие хуки

Вопрос:

Я вызываю функцию ( getEmployees(url) ) внутри a useEffect без второго аргумента.

Я хочу вызывать getEmployees(url ) каждый раз employee , когда добавляется. Как только я добавляю employee или error в качестве второго аргумента, 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
 

Комментарии:

1. К какому крючку вы добавляете аргумент, который вызывает бесконечный рендеринг?

Ответ №1:

Второй аргумент useEffect — это список зависимостей, указывающий React повторно вызывать вашу useEffect функцию при каждом изменении одной из зависимостей.

Если нет зависимостей ( [] ), он просто запустится при монтировании компонента.

Прямо сейчас, если вы ставите employees как зависимость, она будет меняться каждый раз, когда устанавливается ваш employees массив. И вы можете видеть, что в вашей getEmployees функции, которую вы вызываете setEmployees . Вот как вы оказываетесь в своем цикле:

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

Чтобы избежать этого, вы не должны создавать цикл или каким-то образом замыкать его.

Вы говорите, что хотите запускать getEmployees каждый раз при добавлении сотрудника, но из того, что вы показали, нет кода, касающегося добавления сотрудника. Итак, я предполагаю, что, возможно, это происходит на сервере, который вы опрашиваете? Если это так, вам нужно будет найти какой-то способ получить уведомление от сервера — это не будет вопросом простого вызова useEffect , потому что у React не будет возможности узнать, что был добавлен сотрудник. Или в вашем примере отсутствует какой-то соответствующий код.

Ответ №2:

вызовите getEmployees причину employees и error измените. Если вы добавляете сотрудника или ошибку в качестве второго аргумента, это означает, что useEffect выполнит обратный вызов при employees error изменении и . В результате useEffect выполнит обратный вызов при вашем вызове getEmployees . Затем будет вызван обратный вызов getEmployees useEffect . произошла бесконечность.

Я думаю, если вы хотите перезагрузить empolyees, вы можете добавить кнопку обновления

 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 amp;amp; clearTimeout(handle);
   }
}, [])
 

Ответ №3:

Я чувствую, что сотрудники, которые добавляются к данным, которые вы получаете обратно, fetch должны отличаться, и если они разные, вам нужно их разделить, чтобы это работало так, как у вас есть сейчас. Добавления другого состояния для него было бы достаточно, допустим, мы вызываем его setData , поскольку у вас есть его имя data . Теперь setData вместо employees таким образом эффект не запускает бесконечный цикл, а затем обновляет эффект со всеми его зависимостями, и у вас не будет проблем.

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