【问题标题】:react custom hook causing infinite loop反应自定义钩子导致无限循环
【发布时间】:2021-09-08 15:58:36
【问题描述】:

我对反应钩子比较陌生,我正在尝试创建这个自定义钩子来处理我的 API 的 CRUD 操作。

这是挂钩文件:

import React, { useState, useEffect } from "react";

const useApi = (url, headers = { method: "GET" }, payload = null) => {
  
  const [isLoading, setIsLoading] = useState(true);
  const [apiData, setApiData] = useState(null);
  const [serverError, setServerError] = useState(null);
  const [api, setApi] = useState({});

  const list = async () => {
    try {
      const resp = await fetch(url);
      const data = await resp?.json();
      setApiData(data);
      setIsLoading(false);
    } catch (error) {
      setServerError(error);
    } finally {
      setIsLoading(false);
    }
  };

  const create = async () => {
    try {
      const resp = await fetch(url, (headers = { method: "POST" }), payload);
      const data = await resp?.json();
      setApiData(data);
      setIsLoading(false);
    } catch (error) {
      setServerError(error);
    } finally {
      setIsLoading(false);
    }
  };

  setApi({
    ...api,
    list: list,
    create: create
  });

  return { isLoading, apiData, serverError, api };
};

export default useApi;

但是,当我在 useEffect() 钩子内的主要组件中调用 api.list() 时,我得到一个无限循环。

示例组件调用:

import { useEffect } from "react";
import useApi from "./useApi";

export default function App() {
  
  const {
    isLoading: loading,
    apiData: students,
    serverError: error,
    api
  } = useApi("https://59f0f160ce72350012bec011.mockapi.io/students");

  console.log(loading, students, error, api);

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

  return (
    <div className="App">
      <h1>list</h1>
      {loading ? "loading" : students.map((x) => x.name)}
    </div>
  );
}

这是它的沙盒: https://codesandbox.io/s/cocky-chebyshev-d9q89?file=/src/App.js:0-492

谁能帮我理解这个问题? 提前谢谢!

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    这是导致无限循环的原因:

    setApi({
      ...api,
      list: list,
      create: create
    });
    

    您不应该在渲染期间调用 setState()。

    在你的情况下,你不需要为 api 对象useState,你可以在每次渲染时返回它:

    return {
      isLoading,
      apiData,
      serverError,
      api: { list, create }
    };
    

    Here is a link to the fixed sandbox

    另外,另一个警告:此代码将重复调用api.list()

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

    由于api在每次渲染时都会发生变化,它会重复调用api.list()

    这是每次渲染都会改变的对象:

    return { isLoading, apiData, serverError, api };
    

    您可以确保您只调用一次api.list() 使用参考。

    import { useRef } from 'react'
    
    // In the component
    const gotRef = useRef(false)
    useEffect(() => {
      if (!gotRef.current) {
        api.list();
        gotRef.current = true
      }
    }, [api]);
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-10
    • 2020-03-25
    • 2023-01-15
    • 2020-10-27
    • 2021-12-30
    • 2021-03-11
    • 1970-01-01
    相关资源
    最近更新 更多