[英]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.