简体   繁体   English

反应高阶 function 返回钩子

[英]React higher order function to return hook

Currently, I have a custom fetching data hook written in javascript and it works目前,我有一个用 javascript 编写的自定义获取数据钩子,它可以工作

import {useState, useEffect} from 'react';

const useApi = apiName => id => {
  const [response, setResponse] = useState();
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(false);
  const fetching = async () => {
    setLoading(true);
    const data = await fetch(`/api/${apiName}${id ? `/${id}` : ""}`)
      .then((x) => x.json())
      .catch((error) => setError(error));

    setResponse(data);
    setLoading(false);
  };

  useEffect(() => {
    fetching();
  }, [id]);

  return { response, loading, error };
};

Then I can use pass in what api I want to call to get the hook.然后我可以使用传递我想调用的 api 来获取钩子。 For examples:举些例子:

const useCustomer = useApi("customer")
const useHello = useApi("hello")
.....
const {response, loading, error} = useCustomer("id_1")

It works fine.它工作正常。

Then, I try to convert to typescript然后,我尝试转换为 typescript

const useApi = (apiName:string) => (id?:string) => {
  const [response, setResponse] = useState({})
.......
}

and eslint complains that和 eslint 抱怨说

React Hook "useState" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function

I would like to know whats wrong with this approach, I know I can have something like:我想知道这种方法有什么问题,我知道我可以有类似的东西:

const useApi = (apiName:string, id?:string) => {} 

or disable the eslint(react-hooks/rules-of-hooks)或禁用 eslint(react-hooks/rules-of-hooks)

But just curious about whats the potential problems having higher order function of hook since it actually return the response.但只是好奇钩子的高阶 function 的潜在问题是什么,因为它实际上返回了响应。

Thanks谢谢

When you name you function with prefix hooks, eslint thinks of it as a custom hook according to the general convention.当你用prefix钩子命名你的 function 时,eslint 认为它是根据一般约定的自定义钩子。 Now that implements useState in a nested function which is why it gives you an error现在在嵌套的 function 中实现 useState 这就是为什么它会给你一个错误

The best way to write the above code is to not use currying function but pass in the apiName as a param directly编写上述代码的最佳方法是不使用柯里化 function 而是直接将 apiName 作为参数传入

const useApi = (apiName, id) => {
  const [response, setResponse] = useState();
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(false);
  const fetching = async () => {
    setLoading(true);
    const data = await fetch(`/api/${apiName}${id ? `/${id}` : ""}`)
      .then((x) => x.json())
      .catch((error) => setError(error));

    setResponse(data);
    setLoading(false);
  };

  useEffect(() => {
    fetching();
  }, [id]);

  return { response, loading, error };
};

and use it like并像使用它一样

..... ......

const {response, loading, error} = useApi("customer","id_1");

PS Hooks are meant to be an alternative to HOC's and there is no point writing a hook if you use it as an HOC itself PS Hooks 旨在作为 HOC 的替代品,如果您将其用作 HOC 本身,则没有必要编写钩子

There's a much easier way if you don't need the id variable to be in the hook.如果您不需要将 id 变量置于挂钩中,则有一种更简单的方法。 The reason why you get the warning is because your hooks are in your CB instead of your root function.您收到警告的原因是因为您的钩子在您的 CB 中,而不是您的根 function。

Correct Example:正确示例:

const useApi = (apiName:string) => {
  const [response, setResponse] = useState({});

  return (id?: string) => {
    .......
  };
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM