自定义钩子和动态 useEffect 依赖

时间:2021-05-03 08:17:31

标签: reactjs react-hooks use-effect

我在多个组件中使用了这个 useFetch 自定义钩子。


import {useState,useEffect} from 'react'
import {getToken} from './../services/token'

const useFetch = (url) => {

    const [data,setData]       = useState(null);
    const [error,setError]     = useState(null);
    const [loading,setPending] = useState(false);

    useEffect(() => {

        (async()=>{

          const abortCont = new AbortController();
          const token     = await getToken();

          try {

            setPending(true);

            const response = await fetch(url,{
              signal  : abortCont.signal,

              headers : {
                "Content-Type"  : "application/json",
                "Authorization" : "Bearer "+token
              }

            });

            const result    = await response.json();

            setData(result);
            setPending(false);

          } catch (err) {

            if(err.name === 'AbortError'){
                abortCont.abort();
                return;
            }

            setError(String(err));
            setPending(false);

          }

        })()

      }, [])

    return {data,error,loading}
}

export default useFetch;



我将它导入到用户组件中,如下所示。


const {data,error,loading} = useFetch('http://localhost:4040/users');

通常我会像 UseEffect 这样传递 [users.length] 的第二个参数来使用户数据具有反应性,但由于这是一个自定义钩子并在许多组件中使用, 当用户数据更改或更新时,如何使用户数据具有反应性?

Codesandbox Link

1 个答案:

答案 0 :(得分:2)

您可以将依赖数组作为可选参数传递给您的自定义钩子。

const useFetch = async (url, deps) => {

const [data,setData]       = useState(null);
const [error,setError]     = useState(null);
const [loading,setPending] = useState(false);

useEffect(() => {

    (async()=>{

      const abortCont = new AbortController();
      const token     = await getToken();

      try {

        setPending(true);

        const response = await fetch(url,{
          signal  : abortCont.signal,

          headers : {
            "Content-Type"  : "application/json",
            "Authorization" : "Bearer "+token
          }

        });

        const result    = await response.json();

        setData(result);
        setPending(false);

      } catch (err) {

        if(err.name === 'AbortError'){
            abortCont.abort();
            return;
        }

        setError(String(err));
        setPending(false);

      }

    })()

  }, deps || [])

    return {data,error,loading}
}

export default useFetch;

然后这样称呼它

const {data,error,loading} = useFetch('http://localhost:4040/users', [users.length]);

编辑

在您的情况下,您希望对渲染有更多的控制。所以我会说你必须修改你的钩子以支持你安装的组件的设置数据。

const useFetch = async (url, holded, setHolded) => {

const [data,setData]       = useState(null);
const [error,setError]     = useState(null);
const [loading,setPending] = useState(false);

useEffect(() => {

    (async()=>{

      const abortCont = new AbortController();
      const token     = await getToken();

      try {

        setPending(true);

        const response = await fetch(url,{
          signal  : abortCont.signal,

          headers : {
            "Content-Type"  : "application/json",
            "Authorization" : "Bearer "+token
          }

        });

        const result    = await response.json();

        setData(result);
        if(setHolded) {
            setHolded(result);
        }
        setPending(false);

      } catch (err) {

        if(err.name === 'AbortError'){
            abortCont.abort();
            return;
        }

        setError(String(err));
        setPending(false);

      }

    })()

  }, (holded && setHolded && [holded,setHolded,url]) || [url])

    return {data,error,loading}
}

export default useFetch;

然后这样称呼它

const {data,error,loading} = useFetch('http://localhost:4040/users', users, setUsers);