React + Redux,如何在每次调度后渲染,但经过几次?

时间:2017-01-14 02:55:35

标签: javascript reactjs redux react-redux redux-thunk

我正在尝试对商店进行多项更改,但在完成所有更改之前不会进行渲染。我想用redux-thunk做到这一点。

这是我的动作创建者:

function addProp(name, value) {
    return { type:'ADD_PROP', name, value }
}

function multiGeoChanges(...changes) {
    // my goal here is to make multiple changes to geo, and make sure that react doesnt update the render till the end
    return async function(dispatch, getState) {
        for (let change of changes) {
            dispatch(change);
            await promiseTimeout(2000);
        }
    }
}

我像这样派遣我的异步动作创建者:

store.dispatch(multiGeoChanges(addProp(1, "val1"), addProp(2, "val2"), addProp(3, "val3")));

然而,这会导致每个dispatch之后的渲染反应。我是redux-thunk的新手,我从未使用异步中间件,但我认为它可以帮助我。

6 个答案:

答案 0 :(得分:8)

@Kokovin弗拉迪斯拉夫的回答是正确的。添加一些额外的上下文:

Redux将在每次发送后通知所有订阅者。要减少重新渲染,要么调度次数较少,要么使用多种方法之一来“批量”调度和通知。有关详细信息,请参阅有关更新事件的Redux常见问题解答:http://redux.js.org/docs/faq/Performance.html#performance-update-events

我最近还撰写了几篇与此主题相关的博客文章。 Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability讨论了使用thunk的优缺点,并总结了处理调度批处理的几种方法。 Practical Redux Part 6: Connected Lists, Forms, and Performance描述了有关Redux性能的几个关键方面。

最后,还有其他几个库可以帮助批量存储更改通知。有关相关插件的列表,请参阅Store#Store Change SubscriptionsRedux addons catalog部分。特别是,您可能对https://github.com/manaflair/redux-batch感兴趣,这将允许您仅使用一个通知事件来分派一系列操作。

答案 1 :(得分:6)

有很多方法可以实现这个目标:

经典方式:

通常: 操作描述 事实发生了什么 ,但没有指定应用程序的状态如何响应变化。这是减速机的工作。 这也意味着操作不是设置者

因此,您可以描述已发生的事情并积累更改,并发送一个 操作 类似的东西:

const multipleAddProp = (changedProps) =>({
   type:'MULTIPLE_ADD_PROP', changedProps
});

然后对reducer中的动作做出反应:

const geo=(state,action)=>{
   ...
   switch (action.type){
   case 'MULTIPLE_ADD_PROP':
     // apply new props
   ...
   }
}

另一种方式重新渲染至关重要时:

然后你可以考虑限制组件,这些组件可以在状态变化时重新渲染。 例如,您可以使用shouldComponentUpdate来检查组件是否正常 应该是否呈现。 您也可以使用重新选择,以便不重新渲染连接的组件 计算派生数据后......

非标准方式: redux-batched-action

它类似于交易。

在此示例中,订阅者将收到一次通知:

import { batchActions } from 'redux-batched-actions';

const multiGeoChanges=(...arrayOfActions)=> dispatch => {
    dispatch( batchActions(arrayOfActions) );
}

答案 2 :(得分:3)

按照设计,当商店持有的状态改变视图时应该呈现。

您可以通过更新状态一次来避免这种情况。

如果您使用的是promises,则可以使用Promise.all等待所有承诺解析,然后使用计算结果将新操作发送到商店。 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

这样的事情:

Promise.all([p1, p2, p3, p4, p5]).then(changes => { 
  dispatch(changes)
}, err => {
  // deal with error
});

当然,您需要一个可以处理许多道具的动作,例如addManyProps,这应该更新状态一次,从而产生一个渲染。

答案 3 :(得分:0)

redux-batched-actions &#xA ;为redux批处理动作创建者和关联的高阶减少器,它允许为一系列动作批处理订阅者通知。




答案 4 :(得分:0)

稍晚一点,但是我认为这是一个更好的解决方案,它使您可以将meta.batch添加到要批量合并为单个react更新的操作中。另外,这种方法适用于异步操作。

import raf from 'raf'
import { batchedSubscribe } from 'redux-batched-subscribe'

let notify = null
let rafId = null

const shouldBatch = action => action?.meta?.batch

export const batchedSubscribeEnhancer = batchedSubscribe(freshNotify => (notify = freshNotify))

export const batchedSubscribeMiddleware = () => next => action => {
  const resolved = next(action)

  if (notify && rafId === null && !shouldBatch(action)) {
    notify()
  } else if (!rafId) {
    rafId = raf(() => {
      rafId = null
      notify()
    })
  }

  return resolved
}

然后连接到您的商店

mport { applyMiddleware, compose, createStore } from 'redux'
import { batchedSubscribeMiddleware, batchedSubscribeEnhancer } from './batching'

const store = createStore(
  reducer,
  intialState,
  compose(
    batchedSubscribeEnhancer,
    applyMiddleware(batchedSubscribeMiddleware)
  )
)

答案 5 :(得分:0)

在react-redux 7.0.1+中,批处理现已内置。 7.0.1发行说明:

https://github.com/reduxjs/react-redux/releases/tag/v7.0.1

  

批量更新

     

React具有一个unstant_batchedUpdates API,用于对其进行分组   来自同一事件循环刻度的多个更新。反应   团队鼓励我们使用此功能,并且我们更新了内部Redux   订阅处理以利用此API。这也应该有所帮助   通过减少独立渲染的数量来提高性能   由Redux商店更新引起。

function myThunk() {

   return (dispatch, getState) => {

       // should only result in one combined re-render, not two

       batch(() => {

           dispatch(increment());

           dispatch(increment());

       })

   }

}