无法在 React-Native 的 'useEffect' 挂钩中更新用 'useState' 定义的数组
Can't update the array defined with 'useState' in 'useEffect' hook in React-Native
我有一个 feedItems
数组。我想根据 axios
获取请求的响应来设置此数组的项目。在屏幕上,我想显示这个数组元素的信息。所以,在一切之前,我必须设置这个数组,这样我才能显示这个数组元素的信息。
我在发出 API 请求时没有问题,而且我确定 response.data
不为空。但是,当我使用 setFeedItems(...feedItems, response.data[i]);
函数时,出现以下错误。
[Unhandled promise rejection: TypeError: Invalid attempt to spread non-iterable instance.]
代码如下:
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
});
通知:
- 使用回调形式,因为您是根据现有状态更新状态,所以您要确保使用 up-to-date 状态。
- return 值周围的
[]
,因此您正在创建一个数组并将项目分散到其中。
- 它将旧的
feedItems
和新的 response.data
传播到新数组中。
但是如果你想用 response.data
中的数据 replace feedItems
(在这种情况下你可能会这样做),它是更简单:
.then((response) => {
setFeedItems(response.data);
// No `console.log(feedItems)` here, it will show you outdated information
});
此外,在正常情况下,您的 feedItems
将以 空 数组开始,而不是其中包含空对象的数组。所以:
const [feedItems, setFeedItems] = useState([]);
另外:useEffect
不会对 async
函数 returns 的承诺做任何有用的事情(并且会查看 return 值,看看是否它是一个函数),所以你不应该将 async
函数传递给它。由于您已经在使用显式承诺回调,因此没有理由使用 await
和 async
函数。此外,您应该处理 promise 拒绝。
将所有这些放在一起(使用“替换”而不是“附加”选项):
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>
好的,您的代码有几个问题:
useEffect
不应使用 async
函数。你应该在里面创建一个异步函数并在那里调用它。
- 您正在使用
await
和 then
。应该坚持一个。
- 您实际上是在此处添加单个元素
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])
我有一个 feedItems
数组。我想根据 axios
获取请求的响应来设置此数组的项目。在屏幕上,我想显示这个数组元素的信息。所以,在一切之前,我必须设置这个数组,这样我才能显示这个数组元素的信息。
我在发出 API 请求时没有问题,而且我确定 response.data
不为空。但是,当我使用 setFeedItems(...feedItems, response.data[i]);
函数时,出现以下错误。
[Unhandled promise rejection: TypeError: Invalid attempt to spread non-iterable instance.]
代码如下:
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
});
通知:
- 使用回调形式,因为您是根据现有状态更新状态,所以您要确保使用 up-to-date 状态。
- return 值周围的
[]
,因此您正在创建一个数组并将项目分散到其中。 - 它将旧的
feedItems
和新的response.data
传播到新数组中。
但是如果你想用 response.data
中的数据 replace feedItems
(在这种情况下你可能会这样做),它是更简单:
.then((response) => {
setFeedItems(response.data);
// No `console.log(feedItems)` here, it will show you outdated information
});
此外,在正常情况下,您的 feedItems
将以 空 数组开始,而不是其中包含空对象的数组。所以:
const [feedItems, setFeedItems] = useState([]);
另外:useEffect
不会对 async
函数 returns 的承诺做任何有用的事情(并且会查看 return 值,看看是否它是一个函数),所以你不应该将 async
函数传递给它。由于您已经在使用显式承诺回调,因此没有理由使用 await
和 async
函数。此外,您应该处理 promise 拒绝。
将所有这些放在一起(使用“替换”而不是“附加”选项):
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>
好的,您的代码有几个问题:
useEffect
不应使用async
函数。你应该在里面创建一个异步函数并在那里调用它。- 您正在使用
await
和then
。应该坚持一个。 - 您实际上是在此处添加单个元素
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])