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

时间:2021-05-26 12:55:03

标签: 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]))
    })
}, [])

国家边界是传递给组件的道具。如果没有,我该怎么办?

2 个答案:

答案 0 :(得分:5)

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

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

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

.then(data => setBorderCountries(borderCountries => [...borderCountries,data.name]))
//                               ^^^^^^^^^^^^^^^^^^^

...并将 country.borders 添加到 useEffect 依赖项数组。

这将更新您组件的状态每次 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]);
});

无论如何,请注意以下几点:

  1. 您的代码正在成为 fetch API 中的猎物的牺牲品:它只拒绝对 网络 故障的承诺,而不是 HTTP 错误。在调用 ok 之前检查 response 对象上的 .json() 标志以查看是否存在 HTTP 错误。关于in my blog post here的更多信息。

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

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

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

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]);
//  ^^^^^^^^^^^^^^^

或进行一次更新:

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]);
//  ^^^^^^^^^^^^^^^

答案 1 :(得分:-1)

你可以,但这不是一个好习惯。

相关问题