我正在尝试在我的功能组件中使用获取辅助函数,但 React 提示:
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. React component names must start with an uppercase letter react-hooks/rules-of-hooks
我知道功能组件应该以大写字母开头,但是 useFetch 不是组件,它只是一个辅助函数。我究竟做错了什么?我知道我可以通过调用我的函数 UseEffect 而不是 useEffect 来解决这个问题,但我应该这样做吗?
这是我的 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 };
};
和我的 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;
最佳答案
您必须在主渲染函数中使用 useFetch
Hook 。您不能在另一个函数中使用它。您需要调整 useFetch 以单独工作。
这是一个如何做到这一点的例子。在这种情况下,我将在 url 或选项更改时重新获取 useFetch
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
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;
如果您想在响应发生变化时运行一个函数,您可以使用效果:
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]);
关于javascript - 在功能组件中使用钩子(Hook)的辅助函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64689409/