我可以在反应钩子内使用循环吗?

JCe*_*Rdz 2 javascript reactjs react-hooks

我可以这样做吗:

const [borderCountries, setBorderCountries] = useState([])
useEffect(() => {
    country.borders.forEach(c => {
        fetch(`https://restcountries.eu/rest/v2/alpha/${c}`)
            .then(res => res.json())
            .then(data => setBorderCountries([...borderCountries,data.name]))
    })
}, [])
Run Code Online (Sandbox Code Playgroud)

国家边界是传递给组件的道具。如果不是,我能做什么?

T.J*_*der 5

您可以,但不完全是这样,原因如下:

  1. 每个 fetch 操作都会覆盖前一个的结果,因为您是borderCountries直接使用setBorderCountries.
  2. 由于操作取决于道具的值,因此您需要在useEffect依赖项数组中列出该道具。

最小的变化是使用回调版本:

.then(data => setBorderCountries(borderCountries => [...borderCountries,data.name]))
//                               ^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

...并添加country.bordersuseEffect依赖项数组。

这将更新组件的状态,每次一个fetch完成。

或者,收集所有更改并立即应用它们:

Promise.all(
    country.borders.map(c =>
        fetch(`https://restcountries.eu/rest/v2/alpha/${c}`)
            .then(res => res.json())
            .then(data => data.name)
    })
).then(names => {
    setBorderCountries(borderCountries => [...borderCountries, ...names]);
});
Run Code Online (Sandbox Code Playgroud)

无论哪种方式,有几个注意事项:

  1. 您的代码正在成为fetchAPI中的猎物:它只拒绝网络故障的承诺,而不是 HTTP 错误。在调用对象之前检查对象ok上的标志以查看是否存在 HTTP 错误。有关更多信息,请参阅我的博客文章response.json()

  2. 您应该处理fetch失败的可能性(无论是网络错误还是 HTTP 错误)。您的代码中目前没有任何内容处理承诺拒绝。至少,添加一个.catch报告错误。

  3. 由于country.borders是一个属性,您可能希望取消任何先前fetch仍在进行的操作,至少如果它正在获取的边框不在列表中。

将 #1 和 #2 放在一起,但将 #3 作为练习留给读者(尤其是因为您如何/是否处理这取决于您的用例,但对于您将使用的取消部分AbortController),如果您想每次得到结果时更新

const [borderCountries, setBorderCountries] = useState([]);
useEffect(() => {
    country.borders.forEach(c => {
        fetch(`https://restcountries.eu/rest/v2/alpha/${c}`)
            .then(res => {
                if (!res.ok) {
                    throw new Error(`HTTP error ${res.status}`);
                }
                return res.json();
            })
            .then(data => setBorderCountries(borderCountries => [...borderCountries, data.name]))
            //                               ^^^^^^^^^^^^^^^^^^^
            .catch(error => {
                // ...handle and/or report the error...
            });
    });
}, [country.borders]);
//  ^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

或者对于一个更新:

const [borderCountries, setBorderCountries] = useState([]);
useEffect(() => {
    Promise.all(
        country.borders.map(c =>
            fetch(`https://restcountries.eu/rest/v2/alpha/${c}`)
                .then(res => res.json())
                .then(data => data.name)
        })
    )
    .then(names => {
        setBorderCountries(borderCountries => [...borderCountries, ...names]);
    })
    .catch(error => {
        // ...handle and/or report the error...
    });
}, [country.borders]);
//  ^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)