我正在自学 React,我的一个练习是使用axios
从 API 获取国家/地区列表
const fetchCountries = () => {
axios.get("https://restcountries.eu/rest/v2/all").then(response => {
setCountries(response.data);
});
};
React.useEffect(fetchCountries, []);
然后,当用户键入输入时,国家/地区列表会向下过滤。
const handleInputChange = event => {
const filter = event.target.value; // current input value
let matchingCountries = query !== ''
? countries.filter(country => country.name.toLowerCase().indexOf(query.toLowerCase()) !== -1)
: countries;
setQuery(filter);
setMatches(matchingCountries)
console.log('matches', matches)
console.log('query', query)
};
我的目标是,当一个国家匹配时,会触发一个新的 API 请求(获取天气,但这不是我的问题,时间是(。匹配单个国家/地区后,我将渲染有关该国家/地区的一些数据,然后获取并渲染单个国家/地区首都的天气详细信息。
我遇到的问题之一是,当我设置状态时,值似乎总是落后一步。例如,在此代码笔中,当您输入 FRA 时,您应该得到"法国"。但是,我必须输入"FRAN"才能获得匹配。当我不使用状态变量进行匹配时(只是let matches
年(,这不会发生。这成为一个问题,因为我需要在匹配数 = 1 时运行下一个 API 调用,但匹配状态的长度总是错误的。
所以我想知道 1.如何获得匹配国家的正确状态。和 2.什么时候我应该运行第二个 API 调用,而不会进入无限循环。
使用关注点分离的useEffect
解决方案
1个函数应该做 1 件事
handleInputChange
更新状态useEffect
更新状态
但它们不是耦合的。
稍后你可能会有一个名为handleDropdownChange
的新函数,它更新状态
在这种情况下,你不需要修改 useEffect
归根结底,我们(开发人员(不喜欢重写东西
const [countries, setCountries] = React.useState([]);
const [query, setQuery] = React.useState("");
const [matches, setMatches] = React.useState([]);
React.useEffect(() => {
let matchingCountries = query !== ''
? countries.filter(country => country.name.toLowerCase().indexOf(query.toLowerCase()) !== -1)
: countries;
setMatches(matchingCountries)
}, [query]); // called whenever state.query updated
const handleInputChange = event => {
setQuery(event.target.value); // update state
};
const fetchCountries = () => {
axios.get("https://restcountries.eu/rest/v2/all").then(response => {
setCountries(response.data);
});
};
React.useEffect(fetchCountries, []);
并且还有直接使用@Joseph D提供的event.target.value
的解决方案(不推荐(。
唯一的问题是您在handleInputChange()
中使用旧的query
值。
请记住,设置状态是异步的(即不会立即生效(
这是一个更新的版本:
const handleInputChange = event => {
const filter = event.target.value; // current input value
let matchingCountries = filter ? <code here>
// ...
setQuery(filter);
};
更新:
如果有一个国家/地区匹配,则调用天气 api 是将matches
作为useEffect()
中的依赖项。
useEffect(
() => {
async function queryWeatherApi() {
// const data = await fetch(...)
// setData(data)
}
if (matches.length === 1) {
queryWeatherApi();
}
},
[matches]
)
1( 问题的原因在以下行:
let matchingCountries = filter !== ''
? countries.filter(country => country.name.toLowerCase().indexOf(query.toLowerCase()) !== -1)
: countries;
使用query
而不是filter
变量,您的处理程序函数应如下所示:
const handleInputChange = event => {
const filter = event.target.value; // current input value
let matchingCountries = filter !== ''
? countries.filter(country => country.name.toLowerCase().indexOf(filter.toLowerCase()) !== -1)
: countries;
setQuery(filter);
setMatches(matchingCountries)
};
2( 在哪里运行下一个 API 调用: 出于学习目的,我不想建议您使用一些应用程序状态管理库,例如redux
。只是在setFilter
和setQuery
之后立即调用它.它将按预期运行。因为调用 API 也是异步的,所以它将在setQuery
后执行,并setFilter
console.log
同步函数不会发生的事情。