无法更新在 React-Native 中的 'useEffect' 钩子中使用 'useState' 定义的数组



我有一个feedItems数组。我想根据axios获取请求的响应来设置这个数组的项。在屏幕中,我想显示这个数组元素的信息。所以,在做任何事情之前,我必须设置这个数组,这样我就可以显示这个数组元素的信息。

我在发出API请求时没有问题,我确信response.data不是空的。但是,当我使用setFeedItems(...feedItems, response.data[i]);函数时,我会得到以下错误。

[未处理的承诺拒绝:类型错误:传播不可迭代实例的尝试无效。]

这是代码:

const [feedItems, setFeedItems] = useState([{}]);
useEffect(async () => {
console.log("here");
let accessToken = await AsyncStorage.getItem("accessToken");
const response = await axios
.get(
"http://repor****-env-1.eba-nj*******/feed",
{
headers: {
Authorization: "Bearer " + accessToken,
},
}
)
.then((response) => {
for (let i = 0; i < response.data.length; i++) {
setFeedItems(...feedItems, response.data[i]);
}
//console.log(feedArray);
console.log(feedItems);
});
}, []);

问题是将[{}]扩展为setFeedItems的离散参数。要response.data附加到feeditems,请执行以下操作:

.then((response) => {
setFeedItems(feedItems => [...feedItems, ...response.data]);
// No `console.log(feedItems)` here, it will show you outdated information
});

注意:

  • 使用回调表单,因为您正在根据现有状态更新状态,所以您希望确保使用最新状态
  • []围绕返回值,因此您正在创建一个数组并将项分散到其中
  • 它正在将旧的feedItems和新的response.data扩展到新的阵列中

但如果您想用response.data中的数据替换feedItems(在这种特定情况下,您可能会这样做(,它更简单:

.then((response) => {
setFeedItems(response.data);
// No `console.log(feedItems)` here, it will show you outdated information
});

此外,在正常情况下,feedItems将以数组开始,而不是其中包含空对象的数组

const [feedItems, setFeedItems] = useState([]);

另外:useEffect不会对async函数返回的promise做任何有用的事情(并且会查看返回值,看看它是否是一个函数(,所以你不应该向它传递async函数。由于你已经在使用显式promise回调,所以没有理由使用awaitasync函数。此外,你应该处理拒绝承诺的问题。

将所有这些放在一起(使用"替换"而不是"附加"选项(:

const [feedItems, setFeedItems] = useState([{}]);
useEffect(() => {
AsyncStorage.getItem("accessToken").
then(accessToken => axios.get(
"http://repor****-env-1.eba-nj*******/feed",
{
headers: {
Authorization: "Bearer " + accessToken,
},
}))
.then((response) => {
setFeedItems(feedItems => [...feedItems, ...response.data]);
})
.catch(error => {
// ...handle/report the fact an error occurred...
});
}, []);

实例:

const { useState, useEffect } = React;
// Mock `AsyncStorage`
const AsyncStorage = {
getItem() {
return Promise.resolve("some token");
},
};
// Mock `axios`
const axios = {
get() {
return new Promise(resolve => {
setTimeout(() => {
resolve({data: [
{id: 1, text: "Item 1"},
{id: 2, text: "Item 2"},
{id: 3, text: "Item 3"},
{id: 4, text: "Item 4"},
]});
}, 800);
});
},
};
const Example = () => {
const [feedItems, setFeedItems] = useState([]);
useEffect(() => {
AsyncStorage.getItem("accessToken").
then(accessToken => axios.get(
"http://repor****-env-1.eba-nj*******/feed",
{
headers: {
Authorization: "Bearer " + accessToken,
},
}))
.then((response) => {
setFeedItems(response.data);
})
.catch(error => {
// ...handle/report the fact an error occurred...
});
}, []);
return <div>
<div>Item count: {feedItems.length}</div>
{feedItems.map(({id, text}) => <div key={id}>{text}</div>)}
</div>;
};
ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

好吧,您的代码有几个问题:

  1. useEffect不应该使用async函数。您应该在里面创建一个异步函数并在那里调用它
  2. 您正在使用awaitthen。应该坚持一个
  3. 实际上,您在这里添加了一个元素setFeedItems(...feedItems, response.data[i]);,而不是一个数组

尝试使用此setFeedItems([...feedItems, response.data[i]]);

这将修复错误,但不会解决您的问题,因为您正在使用旧的feedItem

为什么不一次用response.data中的所有项更新状态?代替

for (let i = 0; i < response.data.length; i++) {
setFeedItems(...feedItems, response.data[i]);
}

只需:

if (response.data.length) setFeedItems(prevState => [...prevState, ...response.data])

最新更新