我的组件通过调用一个钩子文件来获取数据,钩子文件包含通过API请求的逻辑。 默认情况下,它将调用 API,而无需任何额外的参数。 在 GUI 中,我还显示了一个输入,其中使用可以输入文本。 每次他写一封信,我都想重新获取数据。但我真的不确定如何使用反应和钩子来做到这一点。
我声明了"使用效果"。我看到输入的内容发生了变化。但还有什么呢?我无法从那里调用钩子函数,因为我随后收到此错误:
"React Hook "useFetch" 不能在回调中调用。React Hooks 必须在 React 函数组件或自定义 React Hook 函数 react-hooks/rules-of-hooks 中调用">
这是代码:
hooks.js
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchUrl() {
const response = await fetch(url);
const json = await response.json();
setData(json);
setLoading(false);
}
fetchUrl();
}, [url]);
return [data, loading];
}
export { useFetch };
mycomponent.js
import React, { useState, useEffect } from 'react';
import { useFetch } from "../hooks";
const MyComponent = () => {
useEffect(() => {
console.log('rendered!');
console.log('searchTerm!',searchTerm);
});
const [searchTerm, setSearchTerm] = useState('');
const [data, loading] = useFetch(
"http://localhost:8000/endpoint?${searchTerm}"
);
return (
<>
<h1>Users</h1>
<p>
<input type="text" placeholder="Search" id="searchQuery" onChange={(e) => setSearchTerm(e.target.value)} />
</p>
{loading ? (
"Loading..."
) : (
<div>
{data.users.map((obj) => (
<div key={`${obj.id}`}>
{`${obj.firstName}`} {`${obj.lastName}`}
</div>
))}
</div>
)}
</>
);
}
export default MyComponent;
这就是你在 react 中正确处理搜索的方式。最好在用户登陆您的页面时定义默认搜索术语,否则他们会看到空白页面或看到"正在加载"文本,这不是一个好的用户体验。
const [data, setData] = useState([]);
const [searchTerm, setSearchTerm] = useState("defaultTerm")
在页面的第一个呈现中,我们应该向用户显示"defaultTerm"搜索结果。但是,如果您没有设置防护,则在每次击键中,您的应用程序将发出 api 请求,这会减慢您的应用程序的速度。
为了避免在每次击键中获取数据,我们将"setTimeout"设置为大约 500 毫秒,然后每次用户输入不同的搜索词时,我们必须确保清理以前的 setTimeout 函数,这样我们的应用程序就不会有内存泄漏。
useEffect(() => {
async function fetchUrl() {
const response = await fetch(url);
const json = await response.json();
setData(json);
}
// this is during initial rendering. we have default term but no data yet
if(searchTerm && !data){
fetchUrl();
}else{
//setTimeout returns an id
const timerId=setTimeout(()=>{
if(searchTerm){
fetchUrl}
},500)
// this where we do clean up
return ()=>{clearTimeout(timerId)}
}
}, [url]);
return [data, loading];
}
在 useEffect 中,我们只允许返回一个负责清理的函数。因此,在我们再次调用 useEffect 之前,我们停止了最后一个设置超时。
创建一个函数来处理你的onChange事件,并从中调用你的fetch函数。像这样:
mycomponent.js
import React, { useState, useEffect } from 'react';
import { useFetch } from "../hooks";
const MyComponent = () => {
useEffect(() => {
console.log('rendered!');
console.log('searchTerm!',searchTerm);
});
const [searchTerm, setSearchTerm] = useState('');
const handleChange = e => {
setSearchTerm(e.target.value)
useFetch(
"http://localhost:8000/endpoint?${searchTerm}"
);
}
const [data, loading] = useFetch(
"http://localhost:8000/endpoint?${searchTerm}"
);
return (
<>
<h1>Users</h1>
<p>
<input type="text" placeholder="Search" id="searchQuery" onChange={(e) => handleChange(e)} />
</p>
{loading ? (
"Loading..."
) : (
<div>
{data.users.map((obj) => (
<div key={`${obj.id}`}>
{`${obj.firstName}`} {`${obj.lastName}`}
</div>
))}
</div>
)}
</>
);
}
export default MyComponent;
根据您的要求,您的代码适用于我,在文本框中键入 1 或 2,您将获得不同的结果。
所以基本上API被调用一次,默认值为"searchTerm",然后每次都被onChange调用。
在您当地的尝试这个 -
import React, { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchUrl() {
const response = await fetch(url);
const json = await response.json();
setData(json);
setLoading(false);
}
fetchUrl();
}, [url]);
return [data, loading];
}
export { useFetch };
const MyComponent = () => {
useEffect(() => {
console.log("rendered!");
console.log("searchTerm!", searchTerm);
});
const [searchTerm, setSearchTerm] = useState("");
const [data, loading] = useFetch(
`https://reqres.in/api/users?page=${searchTerm}`
);
return (
<>
<h1>Users</h1>
<p>
<input
type="text"
placeholder="Search"
id="searchQuery"
onChange={e => setSearchTerm(e.target.value)}
/>
</p>
{loading ? (
"Loading..."
) : (
<div>
{data.data.map(obj => (
<div key={`${obj.id}`}>
{`${obj.first_name}`} {`${obj.last_name}`}
</div>
))}
</div>
)}
</>
);
};
export default MyComponent;
你的 useFetch 钩子的设置方式只会在加载时运行一次。您需要以一种可以从仅在搜索词更改时运行的效果函数触发它的方式设置它。