从 useEffect 更新调度中的数据

Hun*_*ter 3 javascript reactjs react-hooks

我正在尝试更新 useEffect 中调度中的数据,但它在控制台中显示警告

React Hook useEffect 缺少依赖项:“dispatch”、“id”和“state.selectedHotel”。包含它们或删除依赖项数组react-hooks/exhaustive-deps

代码:

import { GlobalContext } from "../../../context/globalContext";
const HotelDetail = () => {
    const [state, dispatch] = useContext(GlobalContext);
    const { id } = useParams();

   useEffect(() => {
       const hotelData = async () => {
          try {
              let response = await ServiceGetAllHotels();
              let hotel = response.hotels.filter(hotel => {
                    return hotel.hotelUserName === id;
              });
              dispatch({
                  type: "UPDATE",
                  payload: { selectedHotel: hotel[0] }
              });
          }catch(){}
       };
   }, [])
};
Run Code Online (Sandbox Code Playgroud)

当我添加以下内容时,警告消息消失:

useEffect(() => {
.....
}, [dispatch, state.selectedHotel, id])
Run Code Online (Sandbox Code Playgroud)

我不明白为什么这个错误/警告,为什么当我添加这个时它会消失?

You*_*saf 5

这不是一个错误,而是一个警告,可以帮助您避免由于useEffect钩子在应该运行时未运行而出现的错误。

useEffect默认情况下,hook 在以下之后执行:

  • 初始渲染
  • 每次重新渲染组件时

有时我们不想要这种默认行为;向 hook 传递第二个可选参数useEffect会更改 hook 的默认执行行为useEffect。钩子的第二个参数useEffect称为它的依赖数组,它告诉 React 何时执行useEffect钩子。

在初始渲染后运行一次“useEffect”

我们可以通过将空数组作为第二个参数传递给钩子来实现这一点useEffect

useEffect(() => {
  // code
}, []);
Run Code Online (Sandbox Code Playgroud)

该效果只会执行一次,类似于componentDidMount类组件。

每次其依赖项发生变化时运行“useEffect”

当内部的代码useEffect依赖于状态或道具时,有时您希望在每次状态或道具发生变化时useEffect执行。

我们如何告诉 React 在每次特定状态或 prop 发生变化时运行效果?通过在钩子的依赖数组中添加该状态或道具useEffect

例子:

想象一下,一个Post组件接收帖子 id 作为 prop,并获取与该帖子相关的评论。

您可以编写以下代码来获取评论:

useEffect(() => {
   
   fetch(`/${props.postId}`)
     .then(res => res.json())
     .then(comments => setComments(comments))
     .catch(...)

}, []);
Run Code Online (Sandbox Code Playgroud)

上面的代码有问题:

Post组件第一次渲染时,useEffecthook 将执行,使用作为参数传入的帖子 id 来获取评论。

但是,如果帖子 id 发生变化或者帖子 id 在组件的第一次渲染期间不可用怎么办Post

如果 post id 属性发生变化,Post组件将重新渲染,但不会获取帖子评论useEffect,因为钩子只会在初始渲染后执行一次。

如何解决这个问题?

通过在钩子的依赖数组中添加 post id 属性useEffect

useEffect(() => {
   
   fetch(`/${props.postId}`)
     .then(res => res.json())
     .then(comments => setComments(comments))
     .catch(...)

}, [props.postId]);
Run Code Online (Sandbox Code Playgroud)

现在每次帖子 id 更改时,useEffect都会执行,获取与帖子相关的评论。


这是由于缺少钩子的依赖关系useEffect而可能遇到的问题,React 会向您发出警告。

您不应省略该useEffect钩子或其他钩子的任何依赖项,例如:useMemouseCallback。不忽略它们将使您免受 React 的此类警告,但更重要的是,它将使您免受错误的影响。

状态更新和重新渲染的无限循环

在依赖项数组中添加依赖项时要记住的一件事useEffect是,如果不小心,您的代码可能会陷入无限循环:

useEffect --> state update ---> re-render --> useEffect ....
Run Code Online (Sandbox Code Playgroud)

考虑以下示例:

useEffect(() => {
  const newState = state.map(...);
  setState(data);
}, [state, setState]);
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,如果我们state从依赖项数组中删除 ,我们将收到有关缺少依赖项的警告,如果我们添加state到数组中,我们将获得状态更新和重新渲染的无限循环。

我们可以做什么?

一种方法是跳过state作为挂钩的依赖项useState并使用以下命令禁用警告:

// eslint-disable-next-line react-hooks/exhaustive-deps
Run Code Online (Sandbox Code Playgroud)

上述解决方案可行,但并不理想。

理想的解决方案是以允许您删除导致问题的依赖项的方式更改代码。在这种情况下,我们可以简单地使用带有回调函数的函数形式,setState如下所示:

useEffect(() => {
  setState(currState => currState.map(...));
}, [setState]);
Run Code Online (Sandbox Code Playgroud)

现在我们不需要添加state依赖数组 - 问题解决了!

概括

  • 不要省略useEffect钩子的依赖项
  • 请注意状态更新和重新渲染的无限循环。如果您遇到此问题,请尝试更改代码,以便可以安全地删除导致无限循环的依赖项