反应无法在promise内使用setState正确更新状态

时间:2019-08-17 08:04:50

标签: javascript reactjs promise setstate

我试图在按钮单击时从react组件内的api加载更多数据。该数据应与已经加载的数据合并。加载时,我想显示一个微调器。我正在使用axios并响应钩子组件。

我的代码:

const App = props => {
    const [data, setData] = useState({ ... });
// ...
    function handleLoadMore(uri) {
        setData({...data, isLoadingMore: true})
        axios
            .get(uri)
            .then(response => {
                setData({
                    ...data,
                    items: [...data.items, response.data.items]
                })
            })
            .catch(error => {
                setData({
                    ...data,
                    error: 'An error occured'
                })
            })
            .finally(() => {
                setData({
                    ...data,
                    isLoadingMore: false
                })
            })
    }

我希望这会首先显示微调器,加载新数据,将其与现有数据合并,并显示新的项目列表,但新数据不会合并。 ajax调用返回正确的结果,因此没有问题。我期望的是,如果我删除.finally(..),一切都会按预期进行,甚至微调框也会消失。

然后的问题是,setData如何更新Promise中的状态?在我看来,根本不清除.finally(..)是因为isLoadingMore从未在代码中设置为false,但无论如何它都会更新为false

1 个答案:

答案 0 :(得分:3)

很难说,因为代码不完整,但是我看到两个问题(假设丢失的]只是问题中的错字):

  1. 您不会在response.data.items通话中分散setData
  2. 您正在使用现有状态来设置新状态,但不使用状态设置程序的回调版本来进行设置。该文档与此不一致,但是除非您在某些特定的事件处理程序中(例如{ {1}}),React专门为其处理刷新更新。

所以(请参阅评论):

click

但是,如果您使用的是这样的组合状态,则我会将const App = props => { const [data, setData] = useState({ ... }); // ... function handleLoadMore(uri) { // *** Use callback setData(current => ({...current, isLoadingMore: true})); axios .get(uri) .then(response => { // *** Use callback, spread response.data.items setData(current => ({ ...current, items: [...current.items, ...response.data.items] })); }) .catch(error => { // *** Use callback setData(current => ({...current, error: 'An error occured'})); }) .finally(() => { // *** Use callback setData(current => ({...current, isLoadingMore: false})); }); } } 的清除与上面的内容结合在一起。

isLoadingMore

但是:您应将separate useState calls用于不同的状态项。

const App = props => {
    const [data, setData] = useState({ ... });
    // ...
    function handleLoadMore(uri) {
        setData(current => ({...current, isLoadingMore: true}));
        axios
            .get(uri)
            .then(response => {
                setData(current => ({
                    ...current,
                    items: [...current.items, ...response.data.items],
                    isLoadingMore: false // ***
                }));
            })
            .catch(error => {
                setData(current => ({
                    ...current,
                    error: 'An error occured',
                    isLoadingMore: false // ***
                }));
            });
    }
}

请注意,这如何使更新更加离散,从而减少工作量(不会不断重新散布所有状态项)。