web-dev-qa-db-ja.com

React + Redux、各ディスパッチ後にではなく、数回後にレンダリングする方法は?

ストアに複数の変更を加えようとしていますが、すべての変更が完了するまでレンダリングしません。これを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に慣れていないので、非同期ミドルウェアを使用したことはありませんが、ここで役立つと思いました。

15
Noitidart

目標を達成する方法はいくつかあります。

クラシックな方法:

通常:アクションは、何かが発生した事実を記述しますが、アプリケーションの状態の変化を指定しませんに応じて。これが減速機の仕事です。つまり、アクションはセッターではありません

したがって、何が起こったかを説明し、変更を蓄積し、oneactionを次のようにディスパッチできます。

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

そして、レデューサーのアクションに反応します:

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

別の方法再レンダリングが重要な場合:

次に、コンポーネントを制限することを検討できます。これは、状態の変化時に再レンダリングされる可能性があります。たとえば、shouldComponentUpdateを使用して、コンポーネントをレンダリングする必要があるかどうかを確認できます。また、reselectを使用して、派生データの計算後に接続コンポーネントを再レンダリングしないようにすることもできます...


非標準的な方法:redux-batched-action

トランザクションのようなものです。

この例では、サブスクライバーに1回通知されます。

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

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

@Kokovin Vladislavの答えは正しいです。コンテキストを追加するには:

Reduxはeveryディスパッチ後にすべてのサブスクライバーに通知します。再レンダリングを削減するには、ディスパッチ回数を減らすか、ディスパッチと通知の「バッチ処理」にいくつかのアプローチのいずれかを使用します。詳細については、Reduxをご覧くださいFAQ: http://redux.js.org/docs/faq/Performance.html#performance-update-events =。

私は最近、このトピックに関連するいくつかのブログ投稿も書きました。 イディオマティックRedux:サンク、サガ、抽象化、および再利用性に関する考え は、サンクの使用の長所と短所について説明し、ディスパッチのバッチ処理のいくつかの方法をまとめています。 実用的なReduxパート6:接続リスト、フォーム、およびパフォーマンス は、Reduxのパフォーマンスに関して知っておくべきいくつかの重要な側面を説明しています。

最後に、ストア変更通知の一括処理に役立つライブラリが他にもいくつかあります。関連するアドオンのリストについては、 Store#Store Change Subscriptions my Redux addons catalog のセクションを参照してください。特に、 https://github.com/manaflair/redux-batch に興味があるかもしれません。これにより、単一の通知イベントのみでアクションの配列をディスパッチできます。

9
markerikson

設計により、ストアによって保持される状態は、ビューをレンダリングするときに変更されます。

状態を1回更新することでこれを回避できます。

Promiseを使用している場合は、Promise.allを使用して、すべてのpromiseが解決されるのを待ってから、計算された結果とともに新しいアクションをストアにディスパッチできます。 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のような多くの小道具を処理するアクションが必要です。これにより、状態が1回更新され、1つのレンダリングになります。

3
SagiSergeNadir

React-redux 7.0.1+では、バッチ処理が組み込まれています。 7.0.1のリリースノート:

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

バッチ更新

Reactには、同じイベントループティックからの複数の更新をグループ化するために使用する、unstable_batchedUpdates APIがあります。 Reactチームはこれを使用することを奨励し、このAPIを活用するために内部Reduxサブスクリプション処理を更新しました。これにより、発生する個別のレンダリングの数を減らすことで、パフォーマンスの向上にも役立つはずです。 Reduxストアの更新。

function myThunk() {

   return (dispatch, getState) => {

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

       batch(() => {

           dispatch(increment());

           dispatch(increment());

       })

   }

}
2
Noitidart

redux-batched-actions 一連のアクションのサブスクライバー通知のバッチ処理を可能にする、バッチアクションクリエーターおよび関連するreduxの高次レデューサー。

0
Philip Claren

これには少し遅れますが、これはmeta.batchバッチ処理して1つの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)
  )
)
0
David Bradshaw