简体   繁体   English

在功能组件中使用钩子的辅助函数

[英]Helper function using hooks inside a functional component

I am trying to use fetching helper function inside my functional component but for React complains:我正在尝试在我的功能组件中使用 fetching helper 函数,但 React 抱怨:

src\\components\\Header.js src\\components\\Header.js

Line 19:30: React Hook "useFetch" is called in function "handleSearch" that is neither a React function component nor a custom React Hook function.第 19:30 行:在函数“handleSearch”中调用 React Hook“useFetch”,该函数既不是 React 函数组件,也不是自定义 React Hook 函数。 React component names must start with an uppercase letter react-hooks/rules-of-hooks React 组件名称必须以大写字母开头 react-hooks/rules-of-hooks

I'm aware that functional components should start with a capital letter however, useFetch isn't a components, it's simply a helper function.我知道功能组件应该以大写字母开头,但是 useFetch 不是组件,它只是一个辅助函数。 What am I doing wrong?我究竟做错了什么? I know I can solve this by just calling my function UseEffect instead of useEffect but should I?我知道我可以通过调用我的函数 UseEffect 而不是 useEffect 来解决这个问题,但我应该这样做吗?

Here's my helper.js这是我的 helper.js

import { useState, useEffect } from 'react';

export const GH_BASE_URL = 'https://api.github.com/';

export const useFetch = (url, options) => {
    const [response, setResponse] = useState(null);
    const [error, setError] = useState(null);
    const [isLoading, setIsLoading] = useState(false);
    
    useEffect(() => {
        const fetchData = async () => {
            setIsLoading(true);

            try {
                const res = await fetch(url, options);
                const json = await res.json();
                setResponse(json);
                setIsLoading(false);
            } catch (error) {
                setError(error);
            }
        };
        
        if(url) {
            fetchData();
        }
    }, []);
   
    return { response, error, isLoading };
};

and my Header.js component和我的 Header.js 组件

import React, { useState } from 'react';
import { useFetch, GH_BASE_URL } from '../helpers';

const REPO_SEARCH_URL = `${GH_BASE_URL}/search/repositories?q=`;

function Header(props) {
    const [searchValue, setSearchValue] = useState('');

    function handleChange(event) {
        setSearchValue(event.target.value);
    }

    async function handleSearch(event) {
        event.preventDefault();

        const response = useFetch(`${REPO_SEARCH_URL}${searchValue}`);
    }
    
    return (
        <header>
            <form 
                onSubmit={handleSearch}
                className="container"
            >
                <input
                    value={searchValue}
                    onChange={handleChange}
                    className="search-input"
                    placeholder="Search a repository">
                </input>
            </form>
        </header>
    );
}

export default Header;

You have to use the useFetch hook in the main render function.您必须在主渲染函数中使用useFetch钩子。 You can't use it inside of another function.你不能在另一个函数中使用它。 You'll need to adjust your useFetch to work separately.您需要调整 useFetch 以单独工作。

Here's an example of how to do that.这是一个如何做到这一点的例子。 In this case, I'm making the useFetch refetch when the url or options change在这种情况下,当 url 或选项更改时,我会重新获取 useFetch

helper.js helper.js

import { useState, useEffect } from 'react';

export const GH_BASE_URL = 'https://api.github.com/';

export const useFetch = (url, options) => {
  const [response, setResponse] = useState(null);
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    // Set up aborting
    const controller = new AbortController();
    const signal = controller.signal;
    const fetchData = async () => {
      setIsLoading(true);

      try {
        const res = await fetch(url, { ...options, signal });
        const json = await res.json();
        setResponse(json);
        setIsLoading(false);
      } catch (error) {
        // AbortError means that the fetch was cancelled, so no need to set error
        if (error.name !== 'AbortError') {
          setError(error);
        }
      }
    };

    if (url) {
      fetchData();
    }
    // Clear up the fetch by aborting the old one
    // That way there's no race condition issues here
    return () => {
      controller.abort();
    };
    // url and options need to be in the effect's dependency array
  }, [url, options]);

  return { response, error, isLoading };
};

Header.js头文件.js

import React, { useState } from 'react';
import { useFetch, GH_BASE_URL } from '../helpers';

const REPO_SEARCH_URL = `${GH_BASE_URL}/search/repositories?q=`;

function Header(props) {
  const [searchValue, setSearchValue] = useState('');

  
  function handleChange(event) {
    this.setState({ searchValue: event.target.value });
  }

  // Instead of using the search directly, wait for submission to set it
  const [searchDebounce,setSearchDebounce] = useState('');
  
  async function handleSearch(event) {
    event.preventDefault();
    setSearchDebounce(searchValue);
  }
  // If you want to include the options, you should memoize it, otherwise the fetch will re-run on every render and it'll cause an infinite loop.
  // This will refetch everytime searchDebounce is changed
  const { response, error, isLoading } = useFetch(
    searchDebounce?`${REPO_SEARCH_URL}${searchDebounce}`:''
  );

  return (
    <header>
      <form onSubmit={handleSearch} className="container">
        <input
          value={searchValue}
          onChange={handleChange}
          className="search-input"
          placeholder="Search a repository"
        ></input>
      </form>
    </header>
  );
}

export default Header;

If you want to run a function whenever the response changes, you could use an effect:如果你想在响应发生变化时运行一个函数,你可以使用一个效果:

  useEffect(() => {
    if (error || isLoading) {
      return;
    }
    // Destructure this to prevent a deps issue on the hooks eslint config
    const { responseChanged } = props;
    responseChanged(response);
  }, [response, isLoading, error, props.responseChanged]);

暂无
暂无

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

相关问题 Function 在 React 钩子中的功能组件内 - 性能 - Function inside functional component in React hooks - Performance 挂钩的调用在功能组件内部给出错误挂钩只能在 function 组件的主体内部调用 - Call of hooks is inside of functional component give error Hooks can only be called inside of the body of a function component 兑换 <Class Component> 至 <Stateless Functional Component> 将Hooks与回调函数一起使用 - Convert <Class Component> to <Stateless Functional Component> using Hooks with a callback function 我已经在使用功能组件,但我不断收到错误消息:只能在功能组件的主体内调用钩子 - I'm already using a functional component and I keep getting error : Hooks can only be called inside the body of a function component 使用钩子将 class 组件转换为功能组件 - Convert class component to functional components using hooks 如何将具有构造函数和道具的组件转换为使用钩子和道具的功能组件 - How do I convert a component with a constructor function and props, to a functional component using hooks and props 收到此错误“无效的挂钩调用。 钩子只能在 function 组件的主体内部调用。” 在反应功能组件内? - Getting this error “Invalid hook call. Hooks can only be called inside of the body of a function component.” inside a react functional component? 功能部件的redux挂钩 - redux hooks for functional component React 16:使用钩子和功能组件时,从父级调用子级的 function - React 16: Call children's function from parent when using hooks and functional component 如何使用钩子将功能组件转换为类组件 - How to convert functional component using hooks to class component
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM