我正在从我的 React 组件获取远程数据。数据准备就绪后,将呈现子组件。加载数据时,"数据正在加载..."。将显示文本。
当组件由于props
更改而第二次呈现时,我将以前的数据设置为null
以显示正在加载新数据。
const List = (props) => {
const [items, setItems] = useState(null);
useEffect(() => {
setItems(null);
fetch(`http://some_url_to_fetch_items.com?PAGE=${props.page}`)
.then((data) => {
setItems(data);
})
}, [props.page]);
if (!items) {
return "Data is loading ......."
}
return (
<ul>
{items.map(item => (
<li>{item}</li>
))}
</ul>
)
}
这种方法的问题是,当组件第二次呈现时,setItems(null);
代码不会立即执行(可能是因为useEffect
是异步执行的(,并且组件重新渲染 3 次而不是预期的 2 次:
- 由于道具更改而进行 1-st 重新渲染(但使用旧数据,因为执行
setItems(null)
太晚了( - 最终执行
setItems(null)
后的第二次重新渲染 - 获取数据后第三次重新渲染
我明白我的方法有什么问题。但我看不到其他方法。 必须使用钩子。
有什么想法吗?
一个快速的解决方法是将一个关键道具添加到您的列表中:
<List key={page} page={page} />
当页面的值更改时,将卸载 List 组件,并呈现一个新组件。新的将没有任何以前的数据,因此您只会获得 2 个渲染而不是 3 个。
这意味着您不必再将以前的数据设置为null
。
如果这样做,则需要在调用setItems
之前检查组件是否仍挂载在useEffect
中,否则您将尝试在未挂载的组件上设置状态。你可以写:
if(setItems) {
setItems(data)
}
不过,更改关键道具有点笨拙,所以我会研究其他方法来解决您的问题。
也许您应该将数据传递到列表中,而不是负责获取数据的列表,并将页面状态和数据都放在父组件中?
不过,就目前而言,使用页面更改密钥应该可以工作。
use this method :
useEffect(() => {
fetch(`http://some_url_to_fetch_items.com?PAGE=${props.page}`)
.then((data) => {
setItems(data);
})
}, []);
return (
<ul>
{items? items.map(item => (
<li key={item.id}>{item}</li>
)):"Data is Loading..."}
</ul>
)