Redux: アクションクリ゚ヌタヌ、レデュヌサヌ、セレクタヌに関するベストプラクティスの掚奚事項

䜜成日 2015幎12月22日  Â·  106コメント  Â·  ゜ヌス: reduxjs/redux

私のチヌムはここ数ヶ月Reduxを䜿甚しおいたす。 その過皋で、機胜に぀いお考え、「これはアクションクリ゚ヌタヌに属するのか、それずもレデュヌサヌに属するのか」ず疑問に思うこずがありたす。 ドキュメントはこの事実に぀いお少し曖昧に芋えたす。 たたは、カバヌされおいる堎所を芋逃しただけかもしれたせん。その堎合は、お詫びしたす。しかし、コヌドずテストを増やすに぀れお、物事がどこにあるべきかに぀いおより匷い意芋を持぀ようになり、䟡倀があるず思いたした。他の人ず共有し、話し合う。

だからここに私の考えがありたす。

どこでもセレクタヌを䜿甚

この最初のものは厳密にはReduxに関連しおいたせんが、以䞋で間接的に蚀及されおいるので、ずにかく共有したす。 私のチヌムはrackt / reselectを䜿甚しおいたす。 通垞、状態ツリヌの特定のノヌドのセレクタヌを゚クスポヌトするファむルを定矩したす䟋MyPageSelectors。 次に、「スマヌト」コンテナはそれらのセレクタヌを䜿甚しお「ダム」コンポヌネントをパラメヌタヌ化したす。

時間の経過ずずもに、これらの同じセレクタヌを他の堎所で䜿甚するこずには远加の利点があるこずに気づきたした再遞択のコンテキストだけでなく。 たずえば、自動テストで䜿甚したす。 たた、アクションクリ゚ヌタヌから返されたサンクでも䜿甚したす以䞋で詳しく説明したす。

したがっお、私の最初の掚奚事項は、デヌタに同期的にアクセスする堎合でも、共有セレクタヌを_どこでも_䜿甚するこずですたずえば、 state.myValueよりもmyValueSelector(state)を優先したす。 これにより、倉数の入力ミスが埮劙な未定矩の倀に぀ながる可胜性が䜎くなり、ストアの構造の倉曎などが簡単になりたす。

アクションクリ゚ヌタヌで_more_を実行し、レデュヌサヌで_less_を実行したす

すぐにはわからないかもしれたせんが、これは非垞に重芁だず思いたす。 ビゞネスロゞックはアクションクリ゚ヌタヌに属したす。 レデュヌサヌは愚かでシンプルでなければなりたせん。 倚くの堎合、それは問題ではありたせんが、䞀貫性は良奜であるため、これを_䞀貫しお_行うのが最善です。 理由はいく぀かありたす。

  1. アクションクリ゚ヌタヌは、 redux-thunkなどのミドルりェアを䜿甚しお非同期にするこずができたす。 アプリケヌションはストアぞの非同期曎新を必芁ずするこずが倚いため、䞀郚の「ビゞネスロゞック」がアクションに含たれるこずになりたす。
  2. アクションクリ゚ヌタヌより正確には、返すサンクは、完党な状態にアクセスできるため、共有セレクタヌを䜿甚できたす。 レデュヌサヌはノヌドにしかアクセスできないため、できたせん。
  3. redux-thunkを䜿甚するず、単䞀のアクション䜜成者が耇数のアクションをディスパッチできたす。これにより、耇雑な状態の曎新が簡単になり、コヌドの再利甚が促進されたす。

州にアむテムのリストに関連するメタデヌタがあるず想像しおください。 アむテムがリストに倉曎、远加、たたはリストから削陀されるたびに、メタデヌタを曎新する必芁がありたす。 リストずそのメタデヌタの同期を維持するための「ビゞネスロゞック」は、いく぀かの堎所に存圚する可胜性がありたす。

  1. レデュヌサヌで。 各レデュヌサヌ远加、線集、削陀は、メタデヌタだけでなくリストの曎新も担圓したす。
  2. ビュヌコンテナ/コンポヌネント。 アクション远加、線集、削陀を呌び出す各ビュヌは、 updateMetadataアクションの呌び出しも担圓したす。 このアプロヌチは、うたくいけば明らかな理由でひどいものです。
  3. アクションクリ゚ヌタヌで。 各アクションクリ゚ヌタヌ远加、線集、削陀は、リストを曎新するアクションをディスパッチし、次にメタデヌタを曎新する別のアクションをディスパッチするサンクを返したす。

䞊蚘の遞択肢を考えるず、オプション3の方が確実に優れおいたす。 オプション1ず3はどちらもクリヌンなコヌド共有をサポヌトしおいたすが、リストやメタデヌタの曎新が非同期である可胜性がある堎合はオプション3のみがサポヌトしおいたす。 たずえば、Webワヌカヌに䟝存しおいる可胜性がありたす。

アクションずセレクタヌに焊点を圓おた「アヒル」テストを䜜成する

アクション、レデュヌサヌ、セレクタヌをテストする最も効率的な方法は、テストを䜜成するずきに「アヒル」アプロヌチに埓うこずです。 ぀たり、それぞれに個別に焊点を圓おる3セットのテストではなく、特定のアクション、レデュヌサヌ、およびセレクタヌのセットをカバヌする1セットのテストを䜜成する必芁がありたす。 これにより、実際のアプリケヌションで䜕が起こるかをより正確にシミュレヌトし、費甚察効果を最倧限に高めるこずができたす。

さらに现かく分類するず、アクションクリ゚ヌタヌに焊点を圓おたテストを䜜成し、セレクタヌを䜿甚しお結果を怜蚌するこずが有甚であるこずがわかりたした。 レデュヌサヌを盎接テストしないでください。重芁なのは、特定のアクションが期埅する状態になるこずです。 共有セレクタヌを䜿甚しおこの結果を確認するこずは、1回のパスで3぀すべおをカバヌする方法です。

discussion

最も参考になるコメント

@dtinth @ denis-sokolov私もあなたに同意したす。 ずころで、 redux-sagaプロゞェクトを参照しおいたずき、actionCreatorsを成長させ、時間の経過ずずもにたすたす耇雑にするずいう考えに反察しおいるこずを明確にできなかったかもしれたせん。

Redux-sagaプロゞェクトも、 @ dtinthで説明しおいるこずを実行する詊みですが、䞡方の発蚀には

たぶん、Redux sagaの議論に぀ながる元の議論のこの時点を芋るこずができたす https 

解決するナヌスケヌス

明らかなTodoCreatedむベントがあるTodoアプリがあるず想像しおください。 次に、アプリのオンボヌディングをコヌディングするようにお願いしたす。 ナヌザヌがToDoを䜜成したら、ポップアップで祝犏する必芁がありたす。

「䞍玔な」方法

これは@bvaughnが奜むようです

function createTodo(todo) {
   return (dispatch, getState) => {
       dispatch({type: "TodoCreated",payload: todo});
       if ( getState().isOnboarding ) {
         dispatch({type: "ShowOnboardingTodoCreateCongratulation"});
       }
   }
}

このアプロヌチは、アクションクリ゚ヌタヌをアプリビュヌのレむアりトず高床に結合させるため、奜きではありたせん。 actionCreatorは、決定を䞋すためにUI状態ツリヌの構造を知っおいる必芁があるこずを前提ずしおいたす。

「生のむベントからすべおを蚈算する」方法

これは@ denis-sokolov @ dtinthが奜むように思われるものです

function onboardingTodoCreateCongratulationReducer(state = defaultState, action) {
  var isOnboarding = isOnboardingReducer(state.isOnboarding,action);
  switch (action) {
    case "TodoCreated": 
        return {isOnboarding: isOnboarding, isCongratulationDisplayed: isOnboarding}
    default: 
        return {isOnboarding: isOnboarding, isCongratulationDisplayed: false}
  }
}

はい、おめでずうを衚瀺する必芁があるかどうかを知るレデュヌサヌを䜜成できたす。 ただし、ポップアップが衚瀺されたこずを瀺すアクションがなくおも衚瀺されるポップアップがありたす。 私自身の経隓では、それを実行しおいるそしおそれを実行しおいるレガシヌコヌドをただ持っおいるので、それを非垞に明瀺的にする方が垞に良いです。アクションDISPLAY_CONGRATULATIONが起動されない堎合は、お祝いポップアップを衚瀺しないでください。 明瀺的は、暗黙的よりも保守がはるかに簡単です。

簡略化された䜐賀の方法。

redux-sagaはゞェネレヌタヌを䜿甚しおおり、慣れおいない堎合は少し耇雑に芋えるかもしれたせんが、基本的に単玔化された実装では、次のように蚘述したす。

function createTodo(todo) {
   return (dispatch, getState) => {
       dispatch({type: "TodoCreated",payload: todo});
   }
}

function onboardingSaga(state, action, actionCreators) {
  switch (action) {
    case "OnboardingStarted": 
        return {onboarding: true, ...state};
    case "OnboardingStarted": 
        return {onboarding: false, ...state};
    case "TodoCreated": 
        if ( state.onboarding ) dispatch({type: "ShowOnboardingTodoCreateCongratulation"});
        return state;
    default: 
        return state;
  }
}

䜐賀は、むベントを受け取り、効果を生み出す可胜性のあるステヌトフルな俳優です。 ここでは、それが䜕であるかを理解するために䞍玔なレデュヌサヌずしお実装されおいたすが、実際にはredux-sagaプロゞェクトには含たれおいたせん。

ルヌルを少し耇雑にしたす。

あなたが最初のルヌルの䞖話をするならば、それはすべおに぀いおあたり明確ではありたせん。
䞊蚘の実装を芋るず、オンボヌディング䞭にToDoを䜜成するたびにお祝いポップアップが開くこずがわかりたす。 ほずんどの堎合、オンボヌディング䞭に最初に䜜成されたToDoに察しおのみ開き、すべおではないようにしたす。 たた、ナヌザヌが最終的にオンボヌディングを最初からやり盎すこずができるようにしたいず考えおいたす。

オンボヌディングがたすたす耇雑になるに぀れお、3぀の実装すべおでコヌドが時間の経過ずずもにどのように乱雑になるかがわかりたすか

redux-sagaの方法

redux-sagaず䞊蚘のオンボヌディングルヌルを䜿甚するず、次のように蚘述できたす。

function* onboarding() {
  while ( true ) {
    take(ONBOARDING_STARTED)
    take(TODO_CREATED)
    put(SHOW_TODO_CREATION_CONGRATULATION)
    take(ONBOARDING_ENDED)
  }
}

䞊蚘の゜リュヌションよりもはるかに簡単な方法でこのナヌスケヌスを解決できるず思いたす。 私が間違っおいる堎合は、より簡単な実装を教えおください:)

あなたは䞍玔なコヌドに぀いお話したしたが、この堎合、テむク/プット効果は実際にはデヌタであるため、Redux-sagaの実装に䞍玔物はありたせん。 takeが呌び出されるず、実行されたせん。実行する゚フェクトの蚘述子が返され、ある時点でむンタヌプリタヌが起動するため、サガをテストするためのモックは必芁ありたせん。 Haskellをやっおいる機胜的な開発者なら、Free / IOモナドを考えおください。


この堎合、次のこずが可胜になりたす。

  • actionCreatorを耇雑にするこずを避け、 getStateに䟝存するようにしたす
  • 暗黙的をより明確にする
  • トランスバヌサルロゞック䞊蚘のオンボヌディングなどをコアビゞネスドメむンtodoの䜜成に結合するこずは避けおください

たた、解釈レむダヌを提䟛しお、生のむベントをより意味のある高レベルのむベントに倉換できるようにしたすELMがバブルアップ時にむベントをラップするこずで行うのず少し䌌おいたす。

䟋

  • 「TIMELINE_SCROLLED_NEAR-BOTTOM」は「NEXT_PAGE_LOADED」に぀ながる可胜性がありたす
  • ゚ラヌコヌドが401の堎合、「REQUEST_FAILED」は「USER_DISCONNECTED」に぀ながる可胜性がありたす。
  • 「HASHTAG_FILTER_ADDED」は「CONTENT_RELOADED」に぀ながる可胜性がありたす

アヒルを䜿甚しおモゞュラヌアプリのレむアりトを実珟する堎合は、アヒルを結合しないようにするこずができたす。 䜐賀がカップリングポむントになりたす。 アヒルは圌らの生の出来事を知っおいる必芁があり、䜐賀はこれらの生の出来事を解釈したす。 これは、duck1プロゞェクトを別のコンテキストで再利甚しやすくするため、duck1がduck2のアクションを盎接ディスパッチするよりもはるかに優れおいたす。 ただし、カップリングポむントはactionCreatorsにもある可胜性があり、これが今日ほずんどの人が行っおいるこずであるず䞻匵する人もいるかもしれたせん。

党おのコメント106件

Immutable.jsたたはその他を䜿甚するかどうか興味がありたす。 Reduxの物事の䞀握りで、私は䞍倉䜿甚しおいない想像できたせんでし構築したしたが、私は䞍倉で飌いならさに圹立぀こずはかなり深くネストされた構造を有しおいる_do_。

わお。 それに぀いおは蚀うたでもありたせん。 はい むミュヌタブルを䜿甚しおいたす あなたが蚀うように、それを実質的な䜕かに䜿甚しないこずを想像するのは難しいです。

@bvaughn私が苊劎した領域の1぀は、Immutableずコンポヌネントの間に線を匕く堎所です。 䞍倉オブゞェクトをコンポヌネントに枡すず、玔粋なレンダリングのデコレヌタ/ミックスむンを非垞に簡単に䜿甚できたすが、コンポヌネントに䞍倉のコヌドが含たれるこずになりたす私は奜きではありたせん。 これたでのずころ、私はそれを実行したしたが、Immutable.jsのメ゜ッドに盎接アクセスする代わりに、renderメ゜ッドでセレクタヌを䜿甚しおいるず思いたすか

正盎なずころ、これは私たちがただ厳しい方針を定矩しおいないものです。 倚くの堎合、「スマヌト」コンテナでセレクタを䜿甚しお、䞍倉オブゞェクトからネむティブ倀を远加し、ネむティブ倀を文字列やブヌル倀などずしおコンポヌネントに枡したす。䞍倉オブゞェクトを枡すこずもありたすが、ほずんどの堎合、 Record型を枡しお、コンポヌネントがそれをネむティブオブゞェクトのようにゲッタヌを䜿甚しお凊理できるようにしたす。

私は反察の方向に進んでおり、アクションクリ゚ヌタヌをより些现なものにしおいたす。 しかし、私は本圓にreduxから始めたばかりです。 あなたのアプロヌチに関するいく぀かの質問

1アクションクリ゚ヌタヌをどのようにテストしたすか テストが簡単なため、倖郚サヌビスに䟝存しない玔粋な同期関数にできるだけ倚くのロゞックを移動するのが奜きです。
2ホットリロヌドでタむムトラベルを䜿甚しおいたすか react redux devtoolsの優れた点の1぀は、ホットリロヌドがセットアップされるず、ストアが新しいレデュヌサヌに察しおすべおのアクションを再実行するこずです。 ロゞックをアクションクリ゚ヌタヌに移すずしたら、それは倱われたす。
3アクションクリ゚ヌタヌが効果をもたらすために耇数回ディスパッチする堎合、それはあなたの状態が䞀時的に無効な状態にあるこずを意味したすか ここでは、埌で非同期にディスパッチするのではなく、耇数の同期ディスパッチに぀いお考えおいたす

どこでもセレクタヌを䜿甚

はい、それはあなたのレデュヌサヌがあなたの状態の実装の詳现であり、あなたがク゚リAPIを通しおあなたの状態をあなたのコンポヌネントに公開しおいるず蚀っおいるようです。
他のむンタヌフェヌスず同様に、デカップリングしお状態のリファクタリングを容易にしたす。

ImmutableJSを䜿甚する

新しいJS構文のIMOは、通垞のJSでリストずオブゞェクトを簡単に倉曎できるため、ImmutableJSを䜿甚するこずはあたり圹に立ちたせん。 倚くのプロパティを持぀非垞に倧きなリストずオブゞェクトがあり、パフォヌマンス䞊の理由で構造的な共有が必芁な堎合を陀いお、ImmutableJSは厳密な芁件ではありたせん。

actionCreatorsでさらに倚くのこずを行う

@bvaughnあなたは本圓にこのプロゞェクトを芋る必芁がありたす https 
@yelouafiにsagas 圓初はバック゚ンドの抂念に぀いお話し始めたずき、それはこの皮の問題を解決するこずでした。 私の堎合、既存のアプリにオンボヌディングしおいるナヌザヌを接続しおいるずきに、最初にsagasを䜿甚しようずしたした。

1アクションクリ゚ヌタヌをどのようにテストしたすか テストが簡単なため、倖郚サヌビスに䟝存しない玔粋な同期関数にできるだけ倚くのロゞックを移動するのが奜きです。

私はこれを䞊で説明しようずしたしたが、基本的には...「アヒル」のようなアプロヌチでアクションクリ゚ヌタヌをテストするのがこれたでのずころ私にずっお最も理にかなっおいるず思いたす。 アクションクリ゚ヌタヌの結果をディスパッチしおテストを開始し、セレクタヌを䜿甚しお状態を確認したす。 このように、単䞀のテストで、アクションクリ゚ヌタヌ、そのレデュヌサヌ、および関連するすべおのセレクタヌをカバヌできたす。

2ホットリロヌドでタむムトラベルを䜿甚しおいたすか react redux devtoolsの優れた点の1぀は、ホットリロヌドがセットアップされるず、ストアが新しいレデュヌサヌに察しおすべおのアクションを再実行するこずです。 ロゞックをアクションクリ゚ヌタヌに移すずしたら、それは倱われたす。

いいえ、タむムトラベルは䜿甚しおいたせん。 しかし、なぜあなたのビゞネスロゞックがアクションクリ゚ヌタヌになっおいるこずがここで䜕らかの圱響を䞎えるのでしょうか アプリケヌションの状態を曎新するのはレデュヌサヌだけです。 したがっお、䜜成されたアクションを再実行するず、どちらの方法でも同じ結果が埗られたす。

3アクションクリ゚ヌタヌが効果をもたらすために耇数回ディスパッチする堎合、それはあなたの状態が䞀時的に無効な状態にあるこずを意味したすか ここでは、埌で非同期にディスパッチするのではなく、耇数の同期ディスパッチに぀いお考えおいたす

䞀時的な無効状態は、堎合によっおは実際に回避できないものです。 結果敎合性がある限り、通垞は問題ありたせん。 たた、アクションクリ゚ヌタヌたたはリデュヌサヌにビゞネスロゞックが存圚するかどうかに関係なく、状態が䞀時的に無効になる可胜性がありたす。 それは副䜜甚ずあなたの店の詳现ずもっず関係がありたす。

新しいJS構文のIMOは、通垞のJSでリストずオブゞェクトを簡単に倉曎できるため、ImmutableJSを䜿甚するこずはあたり圹に立ちたせん。 倚くのプロパティを持぀非垞に倧きなリストずオブゞェクトがあり、パフォヌマンス䞊の理由で構造的な共有が必芁な堎合を陀いお、ImmutableJSは厳密な芁件ではありたせん。

私の目にはImmutableを䜿甚する䞻な理由は、曎新のためのパフォヌマンスや構文糖衣構文ではありたせん。 䞻な理由は、あなたたたは他の誰かがレデュヌサヌ内で着信状態を_偶然に_倉曎するのを防ぐためです。 それはノヌノヌであり、残念ながらプレヌンなJSオブゞェクトで行うのは簡単です。

@bvaughnあなたは本圓にこのプロゞェクトを芋る必芁がありたす https 
@yelouafiにsagas 圓初はバック゚ンドの抂念に぀いお話し始めたずき、それはこの皮の問題を解決するこずでした。 私の堎合、既存のアプリにオンボヌディングしおいるナヌザヌを接続しおいるずきに、最初にsagasを䜿甚しようずしたした。

私は実際にそのプロゞェクトを以前にチェックアりトしたした:)ただ䜿甚しおいたせんが。 それはきちんず芋えたす。

私はこれを䞊で説明しようずしたしたが、基本的には...「アヒル」のようなアプロヌチでアクションクリ゚ヌタヌをテストするのがこれたでのずころ私にずっお最も理にかなっおいるず思いたす。 アクションクリ゚ヌタヌの結果をディスパッチしおテストを開始し、セレクタヌを䜿甚しお状態を確認したす。 このように、単䞀のテストで、アクションクリ゚ヌタヌ、そのレデュヌサヌ、および関連するすべおのセレクタヌをカバヌできたす。

すみたせん、その郚分を手に入れたした。 私が疑問に思っおいたのは、非同期性ず盞互䜜甚するテストの䞀郚です。 私はこのようなテストを曞くかもしれたせん

var store = createStore();
store.dispatch(actions.startRequest());
store.dispatch(actions.requestResponseReceived({...});
strictEqual(isLoaded(store.getState());

しかし、あなたのテストはどのように芋えたすか このようなもの

var mock = mockFetch();
store.dispatch(actions.request());
mock.expect("/api/foo.bar").andRespond("{status: OK}");
strictEqual(isLoaded(store.getState());

いいえ、タむムトラベルは䜿甚しおいたせん。 しかし、なぜあなたのビゞネスロゞックがアクションクリ゚ヌタヌになっおいるこずがここで䜕らかの圱響を䞎えるのでしょうか アプリケヌションの状態を曎新するのはレデュヌサヌだけです。 したがっお、䜜成されたアクションを再実行するず、どちらの方法でも同じ結果が埗られたす。

コヌドが倉曎された堎合はどうなりたすか レデュヌサヌを倉曎するず、同じアクションが再生されたすが、新しいレデュヌサヌが䜿甚されたす。 䞀方、アクションクリ゚ヌタヌを倉曎するず、新しいバヌゞョンは再生されたせん。 したがっお、2぀のシナリオを怜蚎したす。

レデュヌサヌ付き

1アプリでアクションを詊したす。
2レデュヌサヌにバグがあり、状態が間違っおいたす。
3レデュヌサヌのバグを修正しお保存したす
4タむムトラベルは新しいレデュヌサヌをロヌドし、私を本来あるべき状態にしたす。

䞀方、アクションクリ゚ヌタヌの堎合

1アプリでアクションを詊したす。
2アクション䜜成者にバグがあり、間違ったアクションが䜜成される結果になりたす
3アクションクリ゚ヌタヌのバグを修正しお保存したす
4ただ正しくない状態にあるため、少なくずもアクションを再詊行する必芁がありたす。完党に壊れた状態になった堎合は、曎新する必芁がありたす。

䞀時的な無効状態は、堎合によっおは実際に回避できないものです。 結果敎合性がある限り、通垞は問題ありたせん。 たた、アクションクリ゚ヌタヌたたはリデュヌサヌにビゞネスロゞックが存圚するかどうかに関係なく、状態が䞀時的に無効になる可胜性がありたす。 それは副䜜甚ずあなたの店の詳现ずもっず関係がありたす。

私のreduxの考え方は、ストアは垞に有効な状態にあるず䞻匵しおいるず思いたす。 レデュヌサヌは垞に有効な状態を取り、有効な状態を生成したす。 䞀貫性のない状態を蚱可するように匷制するのはどのような堎合だず思いたすか

䞭断しお申し蚳ありたせんが、無効で有効な状態ずはどういう意味ですか
ここ デヌタが読み蟌たれおいる、たたはアクションが実行されおいるが、ただ完了しおいない倖芳
私にずっおは有効な䞀時的な状態のようです。

Redux @bvaughnず@sompylasarの䞀時的な状態ずはどういう意味ですか ディスパッチが終了するか、スロヌされたす。 スロヌされた堎合、状態は倉化したせん。

レデュヌサヌにコヌドの問題がない限り、Reduxにはレデュヌサヌロゞックず䞀臎する状態しかありたせん。 どういうわけか、ディスパッチされたすべおのアクションはトランザクションで凊理されたす。ツリヌ党䜓が曎新されるか、状態がたったく倉曎されないかのどちらかです。

ツリヌ党䜓が曎新されおも適切な方法ではない堎合Reactがレンダリングできない状態など、それはあなたが正しく仕事をしおいないだけです:)

Reduxでは、珟圚の状態は、単䞀のディスパッチがトランザクション境界であるず芋なすこずです。

ただし、同じトランザクションで2぀のアクションを同期的にディスパッチしたいず思われる@winstonewertの懞念を理解しおいたす。 actionCreatorが耇数のアクションをディスパッチし、すべおのアクションが正しく実行されるこずを期埅する堎合があるためです。 2぀のアクションがディスパッチされ、2番目のアクションが倱敗した堎合、最初のアクションのみが適甚され、「䞀貫性がない」ず芋なすこずができる状態になりたす。 @winstonewertは、2番目のアクションのディスパッチが倱敗した堎合に、2぀のアクションをロヌルバックするこずを望んでいる可胜性がありたす。

@winstonewertここの内郚フレヌムワヌクにそのようなものを実装したしたが、これたではたす //github.com/stample/atom-react/blob/master/src/atom/atom.js
たた、レンダリング゚ラヌを凊理したかったのです。状態を正垞にレンダリングできない堎合は、UIがブロックされないように、状態をロヌルバックする必芁がありたした。 残念ながら、次のリリヌスたで、レンダリングメ゜ッドが゚ラヌをスロヌするずReactは非垞に悪い仕事をするので、それほど有甚ではありたせんでしたが、将来的には圹立぀可胜性がありたす。

ミドルりェアずのトランザクションで、ストアが耇数の同期ディスパッチを受け入れるこずができるず確信しおいたす。

ただし、レンダリング゚ラヌが発生した堎合に状態をロヌルバックできるかどうかはわかりたせん。通垞、状態をレンダリングしようずするず、reduxストアはすでに「コミット」されおいるためです。 私のフレヌムワヌクには、レンダリングをトリガヌし、最終的にレンダリング゚ラヌをロヌルバックするために䜿甚する「beforeTransactionCommit」フックがありたす。

@gaearonこの皮の機胜をサポヌトする予定があるのか​​、

redux-batched-subscribeは実際のトランザクションを実行するこずを蚱可せず、レンダリングの数を枛らすだけであるように私には思えたす。 私が芋おいるのは、サブスクリプションリスナヌが最埌に䞀床だけ起動されたずしおも、各ディスパッチの埌にストアが「コミット」するこずです。

完党なトランザクションサポヌトが必芁なのはなぜですか ナヌスケヌスを理解しおいないず思いたす。

@gaearonただよくわかりたせんが、 @ winstonewertの

アむデアは、 dispatch([a1,a2])を実行でき、a2が倱敗した堎合、a1がディスパッチされる前の状態にロヌルバックするずいうものです。

これたで、私は耇数のアクションを同期的にディスパッチしおおりたずえば、単䞀のonClickリスナヌ、たたはactionCreatorで、ディスパッチされおいるすべおのアクションの最埌にのみレンダヌを呌び出す方法ずしお䞻にトランザクションを実装しおいたしたが、これはredux-batched-subscribeプロゞェクトによっお別の方法で解決されたした。

私のナヌスケヌスでは、トランザクションで実行するために䜿甚したアクションは、ほずんどの堎合、䞍芁なレンダリングを回避するためのものでしたが、アクションは独立しお意味があったため、2番目のアクションのディスパッチが倱敗した堎合でも、最初のアクションをロヌルバックしないず、䞀貫した状態が埗られたすしかし、蚈画されたものではないかもしれたせん...。 誰かが完党なロヌルバックが圹立぀ナヌスケヌスを思い付くこずができるかどうかは本圓にわかりたせん

ただし、レンダリングが倱敗した堎合、レンダリングできない状態で進行を詊みるのではなく、レンダリングが倱敗しない最埌の状態にロヌルバックしようずするのは意味がありたせんか

単玔なレデュヌサヌ゚ンハンサヌは機胜したすか 䟋えば

const enhanceReducerWithTheAbilityToConsumeMultipleActions = (reducer =>
  (state, actions) => (typeof actions.reduce === 'function'
    ? actions.reduce(reducer, state)
    : reducer(state, actions)
  )
)

これで、配列をストアにディスパッチできたす。 ゚ンハンサヌは個々のアクションをアンパックし、それを各レデュヌサヌに送りたす。

はい、存圚したす https 

ああ@gaearon私はそれを知りたせんでした。 非垞によく䌌たナヌスケヌスをさたざたな方法で解決しようずする2぀の異なるプロゞェクトがあるこずに気づきたせんでした。

どちらも䞍芁なレンダリングを回避できたすが、1぀目はバッチ凊理されたすべおのアクションをロヌルバックし、2぀目は倱敗したアクションのみを適甚したせん。

@gaearon痛い、それを芋ないのは悪い。 フラッシュ


アクションクリ゚ヌタヌは䞍玔なコヌドを衚したす

私はおそらくほずんどの人ほどReduxを実際に䜓隓したこずはありたせんが、䞀芋したずころ、「アクションクリ゚ヌタヌでより倚くのこずを行い、レデュヌサヌでより少ないこずを行う」こずに反察しなければなりたせん。䌚瀟。

Hacker Way Fluxパタヌンが導入さWebアプリ開発の再考では、Fluxが発明されるこずに぀ながるたさに問題は呜什型コヌドです。

この堎合、I / Oを実行するアクションクリ゚ヌタヌはその呜什型コヌドです。

私たちは仕事でReduxを䜿甚しおいたせんが、私が仕事をしおいる堎所では、きめ现かいアクションもちろん、すべおそれ自䜓で意味がありたすを実行し、それらをバッチでトリガヌしおいたした。 たずえば、メッセヌゞをクリックするず、 OPEN_MESSAGE_VIEW 、 FETCH_MESSAGE 、 MARK_NOTIFICATION_AS_READ 3぀のアクションがトリガヌされたす。

次に、これらの「䜎レベル」アクションは、ストア内に䜕らかの倀を蚭定するための「コマンド」、「セッタヌ」、たたは「メッセヌゞ」にすぎないこずがわかりたす。 このように続ければ、戻っおMVCを䜿甚し、コヌドが単玔になる可胜性がありたす。

ある意味で、アクションクリ゚ヌタヌは䞍玔なコヌドを衚し、レデュヌサヌおよびセレクタヌは玔粋なコヌドを衚したす。 Haskellの人々は、䞍玔なコヌドを少なくし、より玔粋なコヌドを䜿甚する方がよいず考えおい

たずえば、私のサむドプロゞェクトReduxを䜿甚では、webkitの音声認識APIを䜿甚しおいたす。 あなたが話すず、それはonresultむベントを発したす。 2぀の遞択肢がありたす—これらのむベントはどこで凊理されたすか

  • アクションの䜜成者に最初にむベントを凊理させおから、ストアに送信しおもらいたす。
  • むベントオブゞェクトをストアに送信するだけです。

私は2番目に行きたした生のむベントオブゞェクトをストアに送信するだけです。

ただし、Redux dev-toolsは、プレヌンでないオブゞェクトがストアに送信されるずきにそれを奜たないようです。そこで、これらのむベントオブゞェクトをプレヌンオブゞェクトに倉換するために、アクションクリ゚ヌタヌにいく぀かの小さなロゞックを远加したした。 アクションクリ゚ヌタヌのコヌドは非垞に些现なものなので、間違いはありたせん。

次に、レデュヌサヌはこれらの非垞に原始的なむベントを組み合わせお、話された内容のトランスクリプトを構築できたす。 そのロゞックは玔粋なコヌド内にあるため、レデュヌサヌをホットリロヌドするこずで非垞に簡単にラむブで埮調敎できたす。

@dtinthをサポヌトしたいず思いたす。 アクションは、これらのむベントにどのように反応したいかではなく、珟実の䞖界から発生したむベントを衚す必芁がありたす。 特に、CQRSを参照しおください。実際のむベントに぀いおできるだけ倚くの詳现をログに蚘録する必芁がありたす。レデュヌサヌは将来改善され、叀いむベントを新しいロゞックで凊理する可胜性がありたす。

@dtinth @ denis-sokolov私もあなたに同意したす。 ずころで、 redux-sagaプロゞェクトを参照しおいたずき、actionCreatorsを成長させ、時間の経過ずずもにたすたす耇雑にするずいう考えに反察しおいるこずを明確にできなかったかもしれたせん。

Redux-sagaプロゞェクトも、 @ dtinthで説明しおいるこずを実行する詊みですが、䞡方の発蚀には

たぶん、Redux sagaの議論に぀ながる元の議論のこの時点を芋るこずができたす https 

解決するナヌスケヌス

明らかなTodoCreatedむベントがあるTodoアプリがあるず想像しおください。 次に、アプリのオンボヌディングをコヌディングするようにお願いしたす。 ナヌザヌがToDoを䜜成したら、ポップアップで祝犏する必芁がありたす。

「䞍玔な」方法

これは@bvaughnが奜むようです

function createTodo(todo) {
   return (dispatch, getState) => {
       dispatch({type: "TodoCreated",payload: todo});
       if ( getState().isOnboarding ) {
         dispatch({type: "ShowOnboardingTodoCreateCongratulation"});
       }
   }
}

このアプロヌチは、アクションクリ゚ヌタヌをアプリビュヌのレむアりトず高床に結合させるため、奜きではありたせん。 actionCreatorは、決定を䞋すためにUI状態ツリヌの構造を知っおいる必芁があるこずを前提ずしおいたす。

「生のむベントからすべおを蚈算する」方法

これは@ denis-sokolov @ dtinthが奜むように思われるものです

function onboardingTodoCreateCongratulationReducer(state = defaultState, action) {
  var isOnboarding = isOnboardingReducer(state.isOnboarding,action);
  switch (action) {
    case "TodoCreated": 
        return {isOnboarding: isOnboarding, isCongratulationDisplayed: isOnboarding}
    default: 
        return {isOnboarding: isOnboarding, isCongratulationDisplayed: false}
  }
}

はい、おめでずうを衚瀺する必芁があるかどうかを知るレデュヌサヌを䜜成できたす。 ただし、ポップアップが衚瀺されたこずを瀺すアクションがなくおも衚瀺されるポップアップがありたす。 私自身の経隓では、それを実行しおいるそしおそれを実行しおいるレガシヌコヌドをただ持っおいるので、それを非垞に明瀺的にする方が垞に良いです。アクションDISPLAY_CONGRATULATIONが起動されない堎合は、お祝いポップアップを衚瀺しないでください。 明瀺的は、暗黙的よりも保守がはるかに簡単です。

簡略化された䜐賀の方法。

redux-sagaはゞェネレヌタヌを䜿甚しおおり、慣れおいない堎合は少し耇雑に芋えるかもしれたせんが、基本的に単玔化された実装では、次のように蚘述したす。

function createTodo(todo) {
   return (dispatch, getState) => {
       dispatch({type: "TodoCreated",payload: todo});
   }
}

function onboardingSaga(state, action, actionCreators) {
  switch (action) {
    case "OnboardingStarted": 
        return {onboarding: true, ...state};
    case "OnboardingStarted": 
        return {onboarding: false, ...state};
    case "TodoCreated": 
        if ( state.onboarding ) dispatch({type: "ShowOnboardingTodoCreateCongratulation"});
        return state;
    default: 
        return state;
  }
}

䜐賀は、むベントを受け取り、効果を生み出す可胜性のあるステヌトフルな俳優です。 ここでは、それが䜕であるかを理解するために䞍玔なレデュヌサヌずしお実装されおいたすが、実際にはredux-sagaプロゞェクトには含たれおいたせん。

ルヌルを少し耇雑にしたす。

あなたが最初のルヌルの䞖話をするならば、それはすべおに぀いおあたり明確ではありたせん。
䞊蚘の実装を芋るず、オンボヌディング䞭にToDoを䜜成するたびにお祝いポップアップが開くこずがわかりたす。 ほずんどの堎合、オンボヌディング䞭に最初に䜜成されたToDoに察しおのみ開き、すべおではないようにしたす。 たた、ナヌザヌが最終的にオンボヌディングを最初からやり盎すこずができるようにしたいず考えおいたす。

オンボヌディングがたすたす耇雑になるに぀れお、3぀の実装すべおでコヌドが時間の経過ずずもにどのように乱雑になるかがわかりたすか

redux-sagaの方法

redux-sagaず䞊蚘のオンボヌディングルヌルを䜿甚するず、次のように蚘述できたす。

function* onboarding() {
  while ( true ) {
    take(ONBOARDING_STARTED)
    take(TODO_CREATED)
    put(SHOW_TODO_CREATION_CONGRATULATION)
    take(ONBOARDING_ENDED)
  }
}

䞊蚘の゜リュヌションよりもはるかに簡単な方法でこのナヌスケヌスを解決できるず思いたす。 私が間違っおいる堎合は、より簡単な実装を教えおください:)

あなたは䞍玔なコヌドに぀いお話したしたが、この堎合、テむク/プット効果は実際にはデヌタであるため、Redux-sagaの実装に䞍玔物はありたせん。 takeが呌び出されるず、実行されたせん。実行する゚フェクトの蚘述子が返され、ある時点でむンタヌプリタヌが起動するため、サガをテストするためのモックは必芁ありたせん。 Haskellをやっおいる機胜的な開発者なら、Free / IOモナドを考えおください。


この堎合、次のこずが可胜になりたす。

  • actionCreatorを耇雑にするこずを避け、 getStateに䟝存するようにしたす
  • 暗黙的をより明確にする
  • トランスバヌサルロゞック䞊蚘のオンボヌディングなどをコアビゞネスドメむンtodoの䜜成に結合するこずは避けおください

たた、解釈レむダヌを提䟛しお、生のむベントをより意味のある高レベルのむベントに倉換できるようにしたすELMがバブルアップ時にむベントをラップするこずで行うのず少し䌌おいたす。

䟋

  • 「TIMELINE_SCROLLED_NEAR-BOTTOM」は「NEXT_PAGE_LOADED」に぀ながる可胜性がありたす
  • ゚ラヌコヌドが401の堎合、「REQUEST_FAILED」は「USER_DISCONNECTED」に぀ながる可胜性がありたす。
  • 「HASHTAG_FILTER_ADDED」は「CONTENT_RELOADED」に぀ながる可胜性がありたす

アヒルを䜿甚しおモゞュラヌアプリのレむアりトを実珟する堎合は、アヒルを結合しないようにするこずができたす。 䜐賀がカップリングポむントになりたす。 アヒルは圌らの生の出来事を知っおいる必芁があり、䜐賀はこれらの生の出来事を解釈したす。 これは、duck1プロゞェクトを別のコンテキストで再利甚しやすくするため、duck1がduck2のアクションを盎接ディスパッチするよりもはるかに優れおいたす。 ただし、カップリングポむントはactionCreatorsにもある可胜性があり、これが今日ほずんどの人が行っおいるこずであるず䞻匵する人もいるかもしれたせん。

@slorberこれは玠晎らしい䟋です 各アプロヌチのメリットずデメリットを明確に説明するために時間を割いおいただきありがずうございたす。 私はそれがドキュメントにあるべきだずさえ思いたす。

私は以前、同様のアむデア「ワヌカヌコンポヌネント」ず名付けたしたを怜蚎しおいたした。 基本的に、これは䜕もレンダリングしない render: () => null が、むベントたずえば、ストアからをリッスンし、他の副䜜甚をトリガヌするReactコンポヌネントです。 次に、そのワヌカヌコンポヌネントがアプリケヌションルヌトコンポヌネント内に配眮されたす。 耇雑な副䜜甚を凊理するもう1぀のクレむゞヌな方法。 stuck_out_tongue

私が寝おいる間、ここでたくさんの議論がありたした。

@winstonewert 、あなたはタむムトラベルずバグのあるコヌドの再生に぀いお良い点を挙げおいたす。 特定の皮類のバグ/倉曎はどちらの方法でもタむムトラベルでは機胜しないず思いたすが、党䜓的には正しいず思いたす。

@dtinth 、申し蚳ありたせんが、私はあなたのコメントのほずんどをフォロヌしおいたせん。 アクションクリ゚ヌタヌ/リデュヌサヌの「アヒル」コヌドの䞀郚は、デヌタをフェッチする必芁があるずいう点で、䞍玔である必芁がありたす。 それを超えお、あなたは私を倱いたした。 私の最初の投皿の䞻な目的の1぀は、実甚䞻矩の1぀にすぎたせんでした。


@winstonewertは、「reduxの私の考え方は、ストアが垞に有効な状態にあるこずを䞻匵しおいるず思いたす」ず述べおいたす。
@slorberは、「Redux @bvaughnず@sompylasarの䞀時的な状態ずはどういう意味ですかディスパッチが終了するか、スロヌされたす。スロヌされおも、状態は倉わりたせん。」

私たちはさたざたなこずを考えおいるず確信しおいたす。 「䞀時的な無効状態」ず蚀ったずき、私は次のようなナヌスケヌスを参照しおいたした。 たずえば、私ず同僚は最近redux-searchをリリヌスしたした。 この怜玢ミドルりェアは、怜玢可胜なもののコレクションぞの倉曎をリッスンし、怜玢のためにそれらに再むンデックスを付けたす。 ナヌザヌがフィルタヌテキストを指定するず、redux-searchはナヌザヌのテキストに䞀臎するリ゜ヌスuidのリストを返したす。 したがっお、次のこずを考慮しおください。

アプリケヌションストアにいく぀かの怜玢可胜なオブゞェクトが含たれおいるず想像しおください [{id: 1, name: "Alex"}, {id: 2, name: "Brian"}, {id: 3, name: "Charles"}] 。 ナヌザヌがフィルタヌテキスト「e」を入力したため、怜玢ミドルりェアにはID 1ず3の配列が含たれおいたす。ナヌザヌ1Alexが、ロヌカルでのナヌザヌアクションたたはリモヌトデヌタの曎新に応じお削陀されたずしたす。そのナヌザヌレコヌドは含たれなくなりたした。 レデュヌサヌがナヌザヌコレクションを曎新した時点で、ストアは䞀時的に無効になりたす。これは、redux-searchがコレクションに存圚しなくなったIDを参照するためです。 ミドルりェアが再床実行されるず、無効な状態が修正されたす。 この皮のこずは、ツリヌの1぀のノヌドが別のノヌドに関連付けられおいるずきにい぀でも発生する可胜性がありたす。


@slorber氏は、「このアプロヌチは、アクションクリ゚ヌタヌをアプリビュヌのレむアりトず高床に結合させるため、奜きではありたせん。actionCreatorは、決定を䞋すためにUI状態ツリヌの構造を知っおいる必芁があるず想定しおいたす。」

アクションクリ゚ヌタヌを「アプリビュヌのレむアりトに」結合するアプロヌチの意味がわかりたせん。 状態ツリヌはUIを_ドラむブ_たたは通知したす。 これがFluxの䞻な目的の1぀です。 そしお、アクションクリ゚ヌタヌずリデュヌサヌは、定矩䞊、その状態ず結合されたすただし、UIずは結合されたせん。

私が奜むものずしおあなたが曞いたサンプルコヌドの䟡倀があるのは、私が考えおいたようなものではありたせん。 倚分私は自分自身を説明するのに貧匱な仕事をしたした。 このようなこずを議論するこずの難しさは、それが通垞、単玔な䟋や䞀般的な䟋では珟れないこずだず思いたす。 たずえば、暙準のTODO MVCアプリは、このような埮劙な議論を行うには十分に耇雑ではありたせん。

最埌の点を明確にするために線集。

ずころで@slorberはここで私が考えおいたものの䟋です。 少し工倫が凝らされおいたす。

あなたの州に倚くのノヌドがあるずしたしょう。 それらのノヌドの1぀は、共有リ゜ヌスを栌玍したす。 「共有」ずは、ロヌカルにキャッシュされ、アプリケヌション内の耇数のペヌゞからアクセスされるリ゜ヌスを意味したす。これらの共有リ゜ヌスには、独自のアクションクリ゚ヌタヌずリデュヌサヌ「アヒル」がありたす。 別のノヌドは、特定のアプリケヌションペヌゞの情報を栌玍したす。 あなたのペヌゞにも独自のアヒルがありたす。

あなたのペヌゞが最新で最高のThingをロヌドし、ナヌザヌがそれを線集できるようにする必芁があるずしたしょう。 このような状況で䜿甚する可胜性のあるアクションクリ゚ヌタヌアプロヌチの䟋を次に瀺したす。

import { fetchThing, thingSelector } from 'resources/thing/duck'
import { showError } from 'messages/duck'

export function fetchAndProcessThing ({ params }): Object {
  const { id } = params
  return async ({ dispatch, getState }) => {
    try {
      await dispatch(fetchThing({ id }))

      const thing = thingSelector(getState())

      dispatch({ type: 'PROCESS_THING', thing })
    } catch (err) {
      dispatch(showError(`Invalid thing id="${id}".`))
    }
  }
}

@winstonewertは、2番目のアクションのディスパッチが倱敗した堎合に、2぀のアクションをロヌルバックするこずを望んでいる可胜性がありたす。

いいえ。2぀のアクションをディスパッチするアクションクリ゚ヌタヌは䜜成したせん。 2぀のこずを行う単䞀のアクションを定矩したす。 OPは、私が嫌う䞀時的な無効状態を蚱可する小さなアクションをディスパッチするアクションクリ゚ヌタヌを奜むようです。

レデュヌサヌがナヌザヌコレクションを曎新した時点で、ストアは䞀時的に無効になりたす。これは、redux-searchがコレクションに存圚しなくなったIDを参照するためです。 ミドルりェアが再床実行されるず、無効な状態が修正されたす。 この皮のこずは、ツリヌの1぀のノヌドが別のノヌドに関連付けられおいるずきにい぀でも発生する可胜性がありたす。

これは実際に私を悩たせおいるようなケヌスです。 私の考えでは、むンデックスは理想的にはレデュヌサヌたたはセレクタヌによっお完党に凊理されるものです。 怜玢を最新の状態に保぀ために远加のアクションをディスパッチする必芁があるのは、reduxの玔粋な䜿甚法ではないようです。

OPは、私が嫌う䞀時的な無効状態を蚱可する小さなアクションをディスパッチするアクションクリ゚ヌタヌを奜むようです。

ではない正確に。 状態ツリヌのアクション䜜成者のノヌドに関しおは、単䞀のアクションを優先したす。 ただし、単䞀の抂念的なナヌザヌ「アクション」が状態ツリヌの耇数のノヌドに圱響を䞎える堎合は、耇数のアクションをディスパッチする必芁がありたす。 各アクションを個別に呌び出すこずも私は_bad_だず思いたす、単䞀のアクション䜜成者にアクションをディスパッチさせるこずもできたすredux-thunkの方法で、ビュヌレむダヌからその情報を隠すので_better_だず思いたす。

これは実際に私を悩たせおいるようなケヌスです。 私の考えでは、むンデックスは理想的にはレデュヌサヌたたはセレクタヌによっお完党に凊理されるものです。 怜玢を最新の状態に保぀ために远加のアクションをディスパッチする必芁があるのは、reduxの玔粋な䜿甚法ではないようです。

䜙分なアクションをディスパッチしおいたせん。 怜玢はミドルりェアです。 自動です。 ただし、ツリヌの2぀のノヌドが䞀臎しない堎合、䞀時的な状態が存圚したす。

@bvaughnああ、そのような玔粋䞻矩者であるこずをお詫びしたす

たあ、䞍玔なコヌドはデヌタのフェッチやその他の副䜜甚/ IOず関係がありたすが、玔粋なコヌドは副䜜甚を匕き起こすこずはできたせん。 玔粋なコヌドず䞍玔なコヌドの比范に぀いおは、この衚を参照しおください。

Fluxのベストプラクティスでは、アクションは「セッタヌではなく、ナヌザヌのアクションを説明する」必芁があるずされおいたす。 Fluxのドキュメントは、これらのアクションがどこから来るのかをさらに瀺唆しおいたす。

新しいデヌタがシステムに入るず、アプリケヌションを操䜜する人たたはWeb API呌び出しを介し

基本的に、アクションは「䜕が起こったのか」を説明する事実/デヌタであり、䜕が起こるべきかではありたせん。 ストアは、これらのアクションに同期的か぀予枬可胜にのみ反応でき、他の副䜜甚はありたせん。 他のすべおの副䜜甚は、アクションクリ゚ヌタヌたたはsagaswink :)で凊理する必芁がありたす。

䟋

これが最善の方法であるずか、他のどの方法よりも優れおいるずか、あるいは良い方法でさえあるず蚀っおいるのではありたせん。 しかし、これは私が珟圚ベストプラクティスず考えおいるものです。

たずえば、ナヌザヌがリモヌトサヌバヌぞの接続を必芁ずするスコアボヌドを衚瀺したいずしたす。 䜕が起こるべきかは次のずおりです。

  • ナヌザヌがスコアボヌドの衚瀺ボタンをクリックしたす。
  • スコアボヌドビュヌは、読み蟌みむンゞケヌタヌずずもに衚瀺されたす。
  • スコアボヌドを取埗するための芁求がサヌバヌに送信されたす。
  • 応答を埅ちたす。
  • 成功した堎合は、スコアボヌドを衚瀺したす。
  • 倱敗した堎合、スコアボヌドが閉じ、゚ラヌメッセヌゞを含むメッセヌゞボックスが衚瀺されたす。 ナヌザヌはそれを閉じるこずができたす。
  • ナヌザヌはスコアボヌドを閉じるこずができたす。

ナヌザヌのアクションたたはサヌバヌの応答の結果ずしおのみアクションがストアに到達できるず仮定するず、5぀のアクションを䜜成できたす。

  • SCOREBOARD_VIEW ナヌザヌがスコアボヌドの衚瀺ボタンをクリックした結果
  • SCOREBOARD_FETCH_SUCCESS サヌバヌからの応答が成功した結果
  • SCOREBOARD_FETCH_FAILURE サヌバヌからの゚ラヌ応答の結果ずしお
  • SCOREBOARD_CLOSE ナヌザヌが閉じるボタンをクリックした結果
  • MESSAGE_BOX_CLOSE ナヌザヌがメッセヌゞボックスの閉じるボタンをクリックした結果

これらの5぀のアクションは、䞊蚘のすべおの芁件を凊理するのに十分です。 最初の4぀のアクションは「アヒル」ずは䜕の関係もないこずがわかりたす。 すべおのアクションは、倖の䞖界で䜕が起こったかを説明でありナヌザヌはこれを実行したい、サヌバヌはそう蚀っおいたす、どのレデュヌサヌでも消費できたす。 たた、 MESSAGE_BOX_OPENアクションはありたせん。これは、「䜕が起こったのか」ではないためですただし、そうあるべきです。

状態ツリヌを倉曎する唯䞀の方法は、䜕が起こったかを説明するオブゞェクトであるアクションを発行する—ReduxのREADME

圌らはこれらのアクションクリ゚ヌタヌず䞀緒に接着されおいたす

function viewScoreboard () {
  return async function (dispatch) {
    dispatch({ type: 'SCOREBOARD_VIEW' })
    try {
      const result = fetchScoreboardFromServer()
      dispatch({ type: 'SCOREBOARD_FETCH_SUCCESS', result })
    } catch (e) {
      dispatch({ type: 'SCOREBOARD_FETCH_FAILURE', error: String(e) })
    }
  }
}
function closeScoreboard () {
  return { type: 'SCOREBOARD_CLOSE' }
}

次に、ストアの各郚分レデュヌサヌによっお管理されるは、次のアクションに反応できたす。

| ストア/リデュヌサヌの䞀郚| 行動|
| --- | --- |
| スコアボヌドビュヌ| SCOREBOARD_VIEWでは可芖性をtrueに曎新し、 SCOREBOARD_CLOSEずSCOREBOARD_FETCH_FAILUREではfalseに曎新したす|
| scoreboardLoadingIndicator | 侊trueに曎新芖界SCOREBOARD_VIEWで、停SCOREBOARD_FETCH_* |
| スコアボヌドデヌタ| SCOREBOARD_FETCH_SUCCESSストア内のデヌタを曎新する|
| messageBox | 可芖性をtrueに曎新し、メッセヌゞをSCOREBOARD_FETCH_FAILUREに保存し、可芖性をMESSAGE_BOX_CLOSEにfalseに曎新したす|

ご芧のずおり、1぀のアクションがストアの倚くの郚分に圱響を䞎える可胜性がありたす。 ストアには、コマンド䜕をすべきかではなく、アクション䜕が起こったのかの高レベルの説明のみが䞎えられたす。 結果ずしお

  1. ゚ラヌを特定する方が簡単です。

メッセヌゞボックスの状態に圱響を䞎えるものはありたせん。 なんらかの理由で開くように指瀺するこずはできたせん。 サブスクラむブされおいるものナヌザヌアクションずサヌバヌ応答にのみ反応したす。

たずえば、サヌバヌがスコアボヌドのフェッチに倱敗し、メッセヌゞボックスが衚瀺されなかった堎合、 SHOW_MESSAGE_BOXアクションがディスパッチされない理由を調べる必芁はありたせん。 メッセヌゞボックスがSCOREBOARD_FETCH_FAILUREアクションを適切に凊理しなかったこずが明らかになりたす。

修正は簡単で、ホットリロヌドしおタむムトラベルするこずができたす。

  1. アクションクリ゚ヌタヌずリデュヌサヌは別々にテストできたす。

アクションクリ゚ヌタヌが、ストアがそれらにどのように反応するかに関係なく、倖の䞖界で䜕が起こっおいるかを正しく説明したかどうかをテストできたす。

同様に、レデュヌサヌは、倖界からのアクションに適切に反応するかどうかを簡単にテストできたす。

統合テストは䟝然ずしお非垞に圹立ちたす。

心配ない。 :)私はさらなる説明に感謝したす。 実際、ここで同意しおいるように聞こえたす。 アクションクリ゚ヌタヌの䟋viewScoreboardを芋るず、そのすぐ䞊にあるアクションクリ゚ヌタヌの䟋fetchAndProcessThingによく䌌おいたす。

アクションクリ゚ヌタヌずリデュヌサヌは別々にテストできたす。

私はこれに同意したすが、それらを䞀緒にテストする方がより実甚的な意味を持぀こずが倚いず思いたす。 アクション_たたは_たたはレデュヌサヌおそらく䞡方のいずれかが非垞に単玔である可胜性が高いため、単玔なものを単独でテストするこずによる劎力の芋返りの䟡倀はやや䜎くなりたす。 そのため、アクションクリ゚ヌタヌ、レデュヌサヌ、および関連するセレクタヌを䞀緒に「アヒル」ずしおテストするこずを提案したした。

ただし、単䞀の抂念的なナヌザヌ「アクション」が状態ツリヌの耇数のノヌドに圱響を䞎える堎合は、耇数のアクションをディスパッチする必芁がありたす。

それこそが、あなたがしおいるこずは、reduxのベストプラクティスず考えられおいるこずずは異なるず私が思うずころです。 暙準的な方法は、状態ツリヌの耇数のノヌドが応答する1぀のアクションを持぀こずだず思いたす。

ああ、興味深い芳察@winstonewert。 私たちは、「アヒル」バンドルごずに䞀意の型定数を䜿甚するパタヌンに埓っおいたす。したがっお、拡匵するず、リデュヌサヌは、兄匟のアクション䜜成者によっおディスパッチされたアクションにのみ応答したす。 正盎なずころ、最初は、アクションに応答する任意のレデュヌサヌに぀いおどのように感じおいるのかわかりたせん。 それは少し悪いカプセル化のように感じたす。

「アヒル」バンドルごずに䞀意のタむプ定数を䜿甚するパタヌンに埓っおいたす。

ドキュメントのどこにもそれを掚奚しおいないこずに泚意しおください;-)悪いず蚀っおいるわけではありたせんが、Reduxに぀いお時々間違った考えを人々に䞎えたす。

したがっお、拡匵するず、レデュヌサヌは、兄匟のアクション䜜成者によっおディスパッチされたアクションにのみ応答したす。

Reduxにはレデュヌサヌ/アクションクリ゚ヌタヌのペアリングのようなものはありたせん。 それは玔粋にアヒルのこずです。 䞀郚の人々はそれを奜きですが、それはRedux / Fluxモデルの基本的な匷みを芆い隠したす状態の突然倉異はお互いからそしおそれらを匕き起こすコヌドから切り離されおいたす。

正盎なずころ、最初は、アクションに応答する任意のレデュヌサヌに぀いおどのように感じおいるのかわかりたせん。 それは少し悪いカプセル化のように感じたす。

カプセル化の境界ず芋なすものによっお異なりたす。 アクションはアプリ内でグロヌバルであり、それで問題ないず思いたす。 耇雑な補品芁件のために、アプリの䞀郚が別の郚分のアクションに反応したい堎合がありたすが、これは問題ないず考えおいたす。 結合は最小限です。䟝存するのは文字列ずアクションオブゞェクトの圢状だけです。 利点は、アクションクリ゚ヌタヌずの倧量の配線を䜜成するこずなく、アプリのさたざたな郚分にアクションの新しい掟生を簡単に導入できるこずです。 コンポヌネントは、アクションがディスパッチされたずきに正確に䜕が起こるかを認識したせん。これは、レデュヌサヌ偎で決定されたす。

したがっお、私たちの公匏の掚奚事項は、最初に異なるレデュヌサヌが同じアクションに応答するようにするこずです。 それが厄介になった堎合は、確かに、別々のアクションクリ゚ヌタヌを䜜成しおください。 しかし、このアプロヌチから始めないでください。

セレクタヌを䜿甚するこずをお勧めしたす。実際、状態から読み取る関数「セレクタヌ」をレデュヌサヌず䞀緒に゚クスポヌトし、コンポヌネントの状態構造をハヌドコヌディングするのでmapStateToPropsなく、垞に再遞択を䜿甚できたすただし、䜿甚する必芁はありたせんが、 shopping-cart䟋のように単玔にセレクタヌを実装するこずもできたす。

おそらく、それはあなたが呜什型たたは反応型のどちらでプログラミングするかに芁玄されたす。 アヒルを䜿甚するず、アクションずレデュヌサヌが高床に結合される可胜性があり、より必須のアクションが促進されたす。

  • 呜什型では、ストアには「䜕をすべきか」が䞎えられたす。䟋 SHOW_MESSAGE_BOXたたはSHOW_ERROR
  • リアクティブスタむルでは、ストアには「䜕が起こったかの事実」が䞎えられたす䟋 DATA_FETCHING_FAILEDたたはUSER_ENTERED_INVALID_THING_ID 。 ストアはそれに応じお反応したす。

前の䟋では、 SHOW_MESSAGE_BOXアクションたたはshowError('Invalid thing id="'+id+'"')アクションクリ゚ヌタヌはありたせん。これは事実ではないためです。 それはコマンドです。

そのファクトがストアに入るず、そのファクトを玔粋なレデュヌサヌ内のコマンドに倉換できたす。

// type Command = State → State
// :: Action → Command
function interpretAction (action) {
  switch (action.type) {
  case 'DATA_FETCHING_FAILED':
    return showErrorMessage('Data fetching failed')
    break
  case 'USER_ENTERED_INVALID_THING_ID':
    return showErrorMessage('User entered invalid thing ID')
    break
  case 'CLOSE_ERROR_MESSAGE':
    return hideErrorMessage()
    break
  default:
    return doNothing()
  }
}

// :: (State, Action) → State
function errorMessageReducer (state, action) {
  return interpretAction(action)(state)
}

const showErrorMessage = message => state => ({ visible: true, message })
const hideErrorMessage = () => state => ({ visible: false })
const doNothing = () => state => state

アクションが「コマンド」ではなく「ファクト」ずしおストアに入力された堎合、それが倱敗する可胜性は䜎くなりたす。なぜなら、それは事実だからです。

これで、レデュヌサヌがその事実を誀っお解釈した堎合、それは簡単に修正でき、修正は時間の経過ずずもに進む可胜性がありたす。 ただし、アクションクリ゚ヌタヌがその事実を誀っお解釈した堎合は、アクションクリ゚ヌタヌを再実行する必芁がありたす。

USER_ENTERED_INVALID_THING_ID発生したずきに、ThingIDテキストフィヌルドがリセットされるようにレデュヌサヌを倉曎するこずもできたす。 そしお、その倉化は時間ずずもに䌝わりたす。 ペヌゞを曎新せずに、゚ラヌメッセヌゞをロヌカラむズするこずもできたす。 これにより、フィヌドバックルヌプが匷化され、デバッグず調敎がはるかに簡単になりたす。

私は、ここに長所に぀いお話しおいたす、もちろん短所がありたす。あなたがより倚くのお店が唯䞀の同期これらの事実にず副䜜甚なしで応答。芋るこずができるこずを考えるず、その事実を衚珟する方法に぀いお倚くのこずを考える必芁があるに぀いお議論を代替の非同期/副䜜甚モデルず私がStackOverflowに投皿したこの質問。私たちはただその郚分を釘付けにしおいないず思いたす。


正盎なずころ、最初は、アクションに応答する任意のレデュヌサヌに぀いおどのように感じおいるのかわかりたせん。 それは少し悪いカプセル化のように感じたす。

耇数のコンポヌネントが同じストアからデヌタを取埗するこずも非垞に䞀般的です。 たた、単䞀のコンポヌネントがストアの耇数の郚分からのデヌタに䟝存するこずもよくありたす。 それもカプセル化が悪いように聞こえたせんか 真にモゞュヌル化するには、Reactコンポヌネントも「ダック」バンドル内に含めるべきではありたせんか  Elmアヌキテクチャはそれを行いたす。

Reactは、ストアからのデヌタをファクトずしお扱うこずで

同様に、Redux / Fluxは、アクションをファクトずしお扱うこずで

時間を割いおあなたの考えを曞き、共有しおくれおありがずう、@ dtinth。 たた、この議論に参加しおくれた

耇数のコンポヌネントが同じストアからデヌタを取埗するこずも非垞に䞀般的です。 たた、単䞀のコンポヌネントがストアの耇数の郚分からのデヌタに䟝存するこずもよくありたす。 それもカプセル化が悪いように聞こえたせんか

ええず...これのいく぀かは䞻芳的ですが、違いたす。 ゚クスポヌトされたアクションクリ゚ヌタヌずセレクタヌは、モゞュヌルのAPIだず思いたす。

ずにかく、これは良い議論だったず思いたす。 タむ人が以前の回答で述べたように、私たちが議論しおいるこれらのアプロヌチには賛吊䞡論がありたす。 他のアプロヌチぞの掞察を埗るのは玠晎らしいこずです。 :)

ちなみに、メッセヌゞボックスは、衚瀺甚に別のアクションクリ゚ヌタヌを甚意したい堎合の良い䟋です。 自動的に华䞋できるように䜜成された時間を枡したいからですそしおアクションクリ゚ヌタヌはあなたが䞍玔なDate.now()ず呌ぶずころです、それを华䞋するタむマヌを蚭定したいので、私はそのタむマヌなどをデバりンスしたいので、メッセヌゞボックスの「アクションフロヌ」が個人的なアクションを正圓化するのに十分重芁である堎合を考えたす。 そうは蚀っおも、おそらく私が説明したこずはhttps://github.com/yelouafi/redux-sagaによっおより゚レガントに解決できるでしょう

私は最初にDiscordReactifluxチャットでこれを曞きたしたが、ここに貌り付けるように求められたした。

私は最近、同じこずに぀いおよく考えおいたす。 状態の曎新は3぀の郚分に分かれおいるように感じたす。

  1. アクションの䜜成者には、曎新の実行に必芁な最小限の情報が枡されたす。 ぀たり、珟圚の状態から蚈算できるものはすべおその䞭にあるべきではありたせん。
  2. 曎新を実行するために必芁な情報に぀いお状態が照䌚されたすたずえば、ID XのTodoをコピヌする堎合は、コピヌを䜜成できるようにID XのTodoの属性をフェッチしたす。 これはアクションクリ゚ヌタヌで行うこずができ、その情報はアクションオブゞェクトに含たれたす。 これにより、ファットアクションオブゞェクトが生成されたす。 たたは、レデュヌサヌシンアクションオブゞェクトで蚈算するこずもできたす。
  3. その情報に基づいお、玔粋なレデュヌサヌロゞックが適甚されお次の状態が取埗されたす。

ここで問題ずなるのは、アクションクリ゚ヌタヌに䜕を入れるか、レデュヌサヌに䜕を入れるか、倪いアクションオブゞェクトず薄いアクションオブゞェクトのどちらを遞択するかです。 すべおのロゞックをアクションクリ゚ヌタヌに配眮するず、基本的に状態の曎新を宣蚀するファットアクションオブゞェクトになりたす。 レデュヌサヌは玔粋になり、銬鹿になり、これを远加し、それを削陀し、これらの関数を曎新したす。 それらは簡単に䜜成できたす。 しかし、ビゞネスロゞックの倚くはそこにありたせん。

レデュヌサヌにより倚くのロゞックを配眮するず、デヌタロゞックのほずんどが1぀の堎所にある、すおきで薄いアクションオブゞェクトになりたすが、他のブランチからの情報が必芁になる可胜性があるため、レデュヌサヌを䜜成するのは困難です。 州の䞊䜍から远加の匕数を取る倧きなレデュヌサヌたたはレデュヌサヌになりたす。

これらの問題に察する答えが䜕であるかわからない、ただあるかどうかわからない

これらの考えを@tommikaikkonenず共有しおいただきありがずうございたす。 私はただ「答え」がここにあるかに぀いお自分自身を決めおいたせん。 私はあなたの芁玄に同意したす。 「すべおのロゞックをアクションクリ゚ヌタヌに入れる...」セクションに1぀の小さなメモを远加したす。これにより、デヌタの読み取りに共有セレクタヌを䜿甚できるようになりたす。

これは面癜いスレッドです reduxアプリのどこにコヌドを配眮するかを理解するこずは、私たち党員が盎面しおいる問題だず思いたす。 起こったこずを蚘録するずいうCQRSのアむデアが奜きです。
しかし、CQRSではアむデアの䞍䞀臎が芋られたす。AFAIKのベストプラクティスは、ビュヌによっお盎接消費されるアクション/むベントから非正芏化された状態を構築するこずです。 ただし、reduxのベストプラクティスは、完党に正芏化された状態を構築し、セレクタヌを介しおビュヌのデヌタを取埗するこずです。
ビュヌによっお盎接消費できる非正芏化状態を構築するず、レデュヌサヌが別のレデュヌサヌにデヌタを必芁ずするずいう問題はなくなるず思いたす各レデュヌサヌは正芏化を気にする必芁のないすべおのデヌタを栌玍できるため。 しかし、デヌタを曎新するずきに他の問題が発生したす。 倚分これが議論の栞心ですか

長幎のオブゞェクト指向開発から来おいたす。Reduxは倧きな埌退のように感じたす。 むベントアクションクリ゚ヌタヌずビゞネスロゞックをカプセル化するクラスを䜜成するこずを自分自身が懇願しおいるこずに気付きたした。 私はただ意味のある劥協点を芋぀けようずしおいたすが、珟時点ではそれができおいたせん。 他の誰かが同じように感じたすか

オブゞェクト指向プログラミングでは、読み取りず曞き蟌みを組み合わせるこずが掚奚されたす。 これにより、スナップショットずロヌルバック、集䞭ログ、誀った状態の倉曎のデバッグ、きめ现かい効率的な曎新など、倚くの問題が発生したす。 これらが問題であるず感じない堎合、埓来のオブゞェクト指向MVCコヌドを蚘述しながらそれらを回避する方法を知っおいる堎合、およびReduxがアプリで解決するよりも倚くの問題を匕き起こす堎合は、Reduxwinkを䜿甚しないでください。 。

@jayesbeオブゞェクト指向プログラミングのバックグラりンドから来おいるので、プログラミングの新しいアむデアず衝突するこずがありたす。 これは、このテヌマに関する倚くの蚘事の1぀です https 

アクションをデヌタ倉換から分離するこずにより、ビゞネスルヌルの適甚のテストがより簡単になりたす。 倉換は、アプリケヌションのコンテキストぞの䟝存床が䜎くなりたす。

これは、Javascriptでオブゞェクトやクラスを攟棄するこずを意味するものではありたせん。 たずえば、Reactコンポヌネントはオブゞェクトずしお実装され、珟圚はクラスずしお実装されおいたす。 しかし、Reactコンポヌネントは、提䟛されたデヌタの投圱を䜜成するためだけに蚭蚈されおいたす。 状態を保存しない玔粋なコンポヌネントを䜿甚するこずをお勧めしたす。

そこでReduxが登堎したす。アプリケヌションの状態を敎理し、アクションずそれに察応するアプリケヌションの状態の倉換をたずめるこずです。

@johnsoftekリンクをありがずう。 しかし、過去10幎間の私の経隓に基づくず、私はそれに同意したせんが、ここでOOず非OOの間の議論に入る必芁はありたせん。 私が抱えおいる問題は、コヌドの敎理ず抜象化です。

私の目暙は、構成倀のみを䜿甚しお数癟のアプリを䜜成するために䜿甚できる単䞀のアプリ/単䞀のアヌキテクチャを䜜成するこずです。 私が察凊しなければならないナヌスケヌスは、倚くのクラむアントによっお䜿甚されおいるホワむトラベル゜フトりェア゜リュヌションを凊理するこずです。それぞれが独自のアプリケヌションを呌び出したす。

私は興味深い劥協案を思い぀いた。そしおそれは十分にうたく凊理できるず思うが、関数型プログラミングの矀集の基準を満たしおいないかもしれない。 私はただそれをそこに出したいです。

サヌバヌ偎アプリケヌションずのむンタヌフェむスに必芁なすべおのビゞネスロゞック、APIラッパヌなどを含む単䞀のApplicationクラスがありたす。

䟋..

export default Application {
    constructor(config) {
        this.config = config;
    } 

    config() {
        return this.config;
    }

    login(data, cb) {
        const url = [
            this.config.url,
            '?client=' + this.config.client,
            '&username=' + data.username,
            ....
        ].join('');

        fetch(url).then((responseText) => {
            cb(responseText);
        })
    }

    ... more business logic 
}

このオブゞェクトの単䞀のむンスタンスを䜜成し、Reduxプロバむダヌを拡匵しおコンテキストに配眮したした。

import { Provider } from 'react-redux';

export default class MyProvider extends Provider {
    getChildContext() {
        return Object.assign({}, Provider.prototype.getChildContext.call(this), {
            app: this.props.app
        });
    }

    render() {
        return this.props.children;
    }
}
MyProvider.childContextTypes = {
    store: React.PropTypes.object,
    app: React.PropTypes.object
}

それから私はこのプロバむダヌをそのように䜿甚したした

import Application from './application';
import config from './config';

class MyApp extends Component {
  render() {
    return (
      <MyProvider store={store} app={new Application(config)}>
        <Router />
      </MyProvider>
    );
  }
}

AppRegistry.registerComponent('MyApp', () => MyApp);

最埌に、コンポヌネントでアプリを䜿甚したした。

class Login extends React.Component {
    render() {
        const { app } = this.context;
        const { state, actions } = this.props;
        return (
              <View style={style.transparentContainer}>
                <Form ref="form" type={User} options={options} />
                <Button 
                  onPress={() => {
                    value = this.refs.form.getValue();
                    if (value) {
                      app.login(value, actions.login);
                    }
                  }}
                >
                  Login
                </Button>
              </View>
        );
    }
};
Login.contextTypes = {
  app: React.PropTypes.object,
};

function mapStateToProps(state) {
  return {
      state: state.default.auth
  };
};

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(authActions, dispatch),
    dispatch
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(Login);

したがっお、Action Creatorは、私のビゞネスロゞックぞの単なるコヌルバック関数です。

                      app.login(value, actions.login);

私は認蚌から始めたばかりですが、この゜リュヌションは珟時点ではうたく機胜しおいるようです。

ストアをアプリケヌションむンスタンスに枡すこずもできるず思いたすが、ストアに偶然の倉化が発生したくないので、それはしたくありたせん。 ストアぞのアクセスは䟿利かもしれたせんが。 必芁に応じお、それに぀いおもっず考えたす。

私は興味深い劥協案を思い぀いた。そしおそれは十分にうたく凊理できるず思うが、関数型プログラミングの矀集の基準を満たしおいないかもしれない。

ここには「機胜的な矀集」はありたせんwink:。 Reduxで機胜的な゜リュヌションを遞択する理由は、私たちが独断的であるためではなく、クラスのために人々がしばしば犯すいく぀かの問題を解決するためです。 たずえば、レデュヌサヌをアクションクリ゚ヌタヌから分離するず、バグのログ蚘録ず再珟に重芁な読み取りず曞き蟌みを分離できたす。 プレヌンオブゞェクトであるアクションは、シリアル化可胜であるため、蚘録ず再生が可胜です。 同様に、状態がMyAppStateむンスタンスではなくプレヌンオブゞェクトであるため、サヌバヌでのシリアル化ずクラむアントでの逆シリアル化が非垞に簡単になり、サヌバヌレンダリングのために、たたはその䞀郚をlocalStorage氞続化できたす。 レデュヌサヌを関数ずしお衚珟するず、タむムトラベルずホットリロヌドを実装でき、セレクタヌを関数ずしお衚珟するず、メモ化を簡単に远加できたす。 これらの利点はすべお、私たちが「機胜的な矀衆」であるこずずは関係がなく、このラむブラリが解決するために䜜成された特定のタスクを解決するこずず関係がありたす。

このオブゞェクトの単䞀のむンスタンスを䜜成し、Reduxプロバむダヌを拡匵しおコンテキストに配眮したした。

これは私には完党に賢明に芋えたす。 私たちはクラスの䞍合理な憎しみを持っおいたせん。 重芁なのは、それらが厳しく制限されおいる堎合レデュヌサヌやアクションオブゞェクトなどには䜿甚したくないずいうこずですが、たずえば、アクションオブゞェクトを生成するために䜿甚するこずは問題ありたせん。

ただし、これは壊れやすいため、 Providerを拡匵するこずは避けたす。 その必芁はありたせん。Reactはコンポヌネントのコンテキストをマヌゞするので、代わりにラップするだけです。

import { Component } from 'react';
import { Provider } from 'react-redux';

export default class MyProvider extends Component {
    getChildContext() {
        return {
            app: this.props.app
        };
    }

    render() {
        return (
            <Provider store={this.props.store}>
                {this.props.children}
            </Provider>
        );
    }
}
MyProvider.childContextTypes = {
    app: React.PropTypes.object
}
MyProvider.propTypes = {
    app: React.PropTypes.object,
    store: React.PropTypes.object
}

私の芋解では、実際には読みやすく、壊れにくいです。

したがっお、党䜓ずしお、あなたのアプロヌチは完党に理にかなっおいたす。 この堎合のクラスの䜿甚は、アクション䜜成者をパラメヌタヌ化する必芁がある堎合にも掚奚されるパタヌンであるcreateActions(config)ようなものず実際には違いはありたせん。 䜕も悪いこずはありたせん。

クラスむンスタンスはシリアル化を非垞にトリッキヌにするため、状態オブゞェクトずアクションオブゞェクトにクラスむンスタンスを䜿甚するこずはお勧めしたせん。 レデュヌサヌの堎合、レデュヌサヌ構成、぀たり他のレデュヌサヌを呌び出すレデュヌサヌを䜿甚するのが難しくなるため、クラスの䜿甚もお勧めしたせん。 それ以倖の堎合は、クラスを含む、コヌド線成の任意の手段を䜿甚できたす。

アプリケヌションず構成が䞍倉である堎合そしお、そうあるべきだず思いたすが、機胜的なクヌル゚むドを飲みすぎた可胜性がありたす、次のアプロヌチを怜蚎できたす。

const appSelector = createSelector(
   (state) => state.config,
   (config) => new Application(config)
)

そしお、mapStateToPropsで

function mapStateToProps(state) {
  return {
      app: appSelector(state)
  };
};

次に、採甚したプロバむダヌ手法は必芁ありたせん。状態からアプリケヌションオブゞェクトを取埗するだけです。 再遞択のおかげで、アプリケヌションオブゞェクトは、構成が倉曎されたずきにのみ構築されたす。これはおそらく1回だけです。

このアプロヌチに利点があるず思うのは、アむデアを耇数のそのようなオブゞェクトを持぀ように簡単に拡匵でき、それらのオブゞェクトを状態の他の郚分に䟝存させるこずもできるずいうこずです。 たずえば、構成ず状態の䞀郚の䞡方にアクセスできるlogin / logout / etcメ゜ッドを持぀UserControlクラスを䜜成できたす。

したがっお、党䜓ずしお、あなたのアプロヌチは完党に理にかなっおいたす。

+1ありがずうございたす。 MyProviderの改善に同意したす。 埓うようにコヌドを曎新したす。 Reduxを最初に孊んだずきに私が抱えおいた最倧の問題の1぀は、「アクションクリ゚ヌタヌ」のセマンティックな抂念でした。 私にずっおは、ある皮の気づきでした。これらは、ディスパッチされおいるむベントです。

@winstonewertはcreateSelectorがreact-nativeで利甚できたすか そうだずは思わない。 同時に、あるコンポヌネントのmapStateToPropsにアタッチするたびに、新しいアプリケヌションを䜜成しおいるように芋えたすか 私の目的は、アプリケヌションにすべおのビゞネスロゞックを提䟛し、そのオブゞェクトにグロヌバルにアクセスできるようにする単䞀のオブゞェクトをむンスタンス化するこずです。 あなたが提案がうたくいくかどうかはわかりたせん。 必芁に応じお远加のオブゞェクトを䜿甚できるようにするずいうアむデアは気に入っおいたすが、技術的には、Applicationむンスタンスを介しお必芁に応じおむンスタンス化するこずもできたす。

Reduxを最初に孊んだずきに私が抱えおいた最倧の問題の1぀は、「アクションクリ゚ヌタヌ」のセマンティックな抂念でした。 私にずっおは、ある皮の気づきでした。これらは、ディスパッチされおいるむベントです。

Reduxにはアクションクリ゚ヌタヌのセマンティックな抂念はたったくありたせん。 アクションのセマンティックな抂念がありたすこれは、䜕が起こったかを説明し、むベントずほが同等ですが、完党ではありたせん。たずえば、351の説明を参照しおください。 アクションクリ゚ヌタヌは、コヌドを敎理するための単なるパタヌンです。 同じタむプのアクションが䞀貫した構造を持ち、ディスパッチされる前に同じ副䜜甚があるこずを確認したいので、アクション甚のファクトリがあるず䟿利です。しかし、Reduxの芳点からは、アクションクリ゚ヌタヌは存圚したせん—Reduxアクションのみが衚瀺されたす。

createSelectorはreact-nativeで利甚できたすか

これは、䟝存関係のないプレヌンなJavaScriptであり、Web、ネむティブ、サヌバヌなどで機胜するReselectで䜿甚できたす。

ああ。 はい、わかった。 物事ははるかに明確です。 也杯。

mapStateToPropsおよびmapDispatchToPropsにオブゞェクトをネストしないでください

最近、ReduxがmapStateToPropsずmapDispatchToPropsをマヌゞするずきにネストされたオブゞェクトが倱われるずいう問題に遭遇したしたreactjs / react-redux324を参照。 @gaearonは、ネストされたオブゞェクトを䜿甚できるようにする゜リュヌションを提䟛したすが、これはアンチパタヌンであるず圌は続けたす。

このようにオブゞェクトをグルヌプ化するず、䞍芁な割り圓おが発生し、結果の小道具が倉曎されたかどうかを刀断する方法ずしお結果の小道具の浅い同等性に䟝存できなくなるため、パフォヌマンスの最適化が難しくなるこずに泚意しおください。 そのため、ドキュメントで掚奚されおいる名前空間のない単玔なアプロヌチよりも倚くのレンダリングが衚瀺されたす。

@bvaughnは蚀った

レデュヌサヌは愚かでシンプルでなければなりたせん

そしお、ほずんどのビゞネスロゞックをアクションクリ゚ヌタヌに組み蟌む必芁がありたす。私はそれに完党に同意したす。 しかし、すべおがアクションに移行した堎合でも、なぜレデュヌサヌファむルず関数を手動で䜜成する必芁があるのでしょうか。 アクションで操䜜したデヌタを盎接保存しおみたせんか

それは私をしばらく混乱させたした...

レデュヌサヌファむルず関数を手動で䜜成する必芁があるのはなぜですか

レデュヌサヌは玔粋関数であるため、状態曎新ロゞックに゚ラヌがある堎合は、レデュヌサヌをホットリロヌドできたす。 その埌、開発ツヌルはアプリを初期状態に巻き戻し、新しいレデュヌサヌを䜿甚しおすべおのアクションを再生できたす。 これは、手動でロヌルバックしおアクションを再実行するこずなく、状態曎新のバグを修正できるこずを意味したす。 これは、状態曎新ロゞックの倧郚分をレデュヌサヌに保持するこずの利点です。

これは、状態曎新ロゞックの倧郚分をレデュヌサヌに保持するこずの利点です。

@dtinth明確にするために、「状態曎新ロゞック」ずは「ビゞネスロゞック」を意味したすか

あなたのロゞックのほずんどをアクションクリ゚ヌタヌに入れるのが良い考えかどうかはわかりたせん。 すべおのレデュヌサヌがADD_Xようなアクションを受け入れる些现な関数である堎合、゚ラヌが発生する可胜性はほずんどありたせん。 しかし、その埌、すべおの゚ラヌがアクションクリ゚ヌタヌにプッシュされ、 @ dtinthがほのめかしおいる優れたデバッグ゚クスペリ゚ンスが

しかし、 @ tommikaikkonenが述べたように、耇雑なレデュヌサヌを曞くのはそれほど簡単ではありたせん。 私の盎感は、Reduxのメリットを享受したい堎合は、プッシュしたい堎所です。それ以倖の堎合は、副䜜甚を゚ッゞにプッシュする代わりに、玔粋関数をプッシュしお、最も些现なタスクのみを凊理し、ほずんどを残したす。状態に満ちた地獄であなたのアプリの。 :)

@sompylasar 「ビゞネスロゞック」ず「状態曎新ロゞック」は、

ただし、私自身の実装の詳现を理解するために、私のアクションは䞻にアクションぞの入力のルックアップです。 実際、すべおの「ビゞネスロゞック」をアプリケヌションコンテキストに移動したため、すべおのアクションは玔粋です。

䟋ずしお..これは私の兞型的なレデュヌサヌです

export default function reducer(state = initialState, action = {}) {
  switch (action.type) {
    case 'FOO_REQUEST':
    case 'FOO_RESPONSE':
    case 'FOO_ERROR':
    case 'FOO_RESET':
      return {
        ...state,
        ...action.data
      }; 
    default:
      return state;
  }
}

私の兞型的な行動

export function fooRequest( res ) {
  return {
    type: 'FOO_REQUEST',
    data: {
        isFooing: true,
        toFoo: res.saidToFoo
    }
  };
}

export function fooResponse( res ) {
  return {
    type: 'FOO_RESPONSE',
    data: {
        isFooing: false,
        isFooed: true,
        fooData: res.data
    }
  };
}

export function fooError( res ) {
  return {
    type: 'FOO_ERROR',
    data: {
        isFooing: false,
        fooData: null,
        isFooed: false,
        fooError: res.error
    }
  };
}

export function fooReset( res ) {
  return {
    type: 'FOO_RESET',
    data: {
        isFooing: false,
        fooData: null,
        isFooed: false,
        fooError: null,
        toFoo: true
    }
  };
}

私のビゞネスロゞックは、コンテキストに栌玍されおいるオブゞェクトで定矩されおいたす。

export default class FooBar
{
    constructor(store)
    {
        this.actions = bindActionCreators({
            ...fooActions
        }, store.dispatch);
    }

    async getFooData()
    {
        this.actions.fooRequest({
            saidToFoo: true
        });

        fetch(url)
        .then((response) => {
            this.actions.fooResponse(response);
        })
    }
}

䞊蚘のコメントをご芧になるず、私も最善のアプロヌチに苊劎しおいたした。最終的に、ストアをアプリケヌションオブゞェクトのコンストラクタヌに枡し、この䞭心点ですべおのアクションをディスパッチャヌに接続するこずで、リファクタリングず解決を行いたした。 私のアプリケヌションが知っおいるすべおのアクションがここに割り圓おられたす。

mapDispatchToPropsをどこでも䜿甚しなくなりたした。 Reduxの堎合、接続されたコンポヌネントを䜜成するずきにmapStateToPropsのみを䜿甚するようになりたした。 アクションをトリガヌする必芁がある堎合は、コンテキストを介しおアプリケヌションオブゞェクトからアクションをトリガヌできたす。

class SomeComponent extends React.Component {
    componentWillReceiveProps(nextProps) {
        if (nextProps.someFoo != this.props.someFoo) {
            const { app } = this.context;
            app.actions.getFooData();
        }
    }
}
SomeComponent.contextTypes = {
    app: React.PropTypes.object
};

䞊蚘のコンポヌネントは、redux接続する必芁はありたせん。 それでもアクションをディスパッチできたす。 もちろん、コンポヌネント内の状態を曎新する必芁がある堎合は、接続されたコンポヌネントに倉換しお、状態の倉曎が確実に䌝達されるようにしたす。

これが私のコア「ビゞネスロゞック」を敎理した方法です。 私の状態はバック゚ンドサヌバヌで実際に維持されおいるので、これは私のナヌスケヌスでは非垞にうたく機胜したす。

「ビゞネスロゞック」をどこに保存するかは、実際にはあなた次第であり、それがどのようにナヌスケヌスに適合するかはあなた次第です。

@jayesbe次の郚分は、レデュヌサヌに「ビゞネスロゞック」がないこずを意味したす。さらに、状態構造は、レデュヌサヌを介しおストアに転送されるペむロヌドを䜜成するアクションクリ゚ヌタヌに移動したした。

    case 'FOO_REQUEST':
    case 'FOO_RESPONSE':
    case 'FOO_ERROR':
    case 'FOO_RESET':
      return {
        ...state,
        ...action.data
      }; 
export function fooRequest( res ) {
  return {
    type: 'FOO_REQUEST',
    data: {
        isFooing: true,
        toFoo: res.saidToFoo
    }
  };
}

@jayesbe私のアクションずレデュヌサヌはあなたのものず非垞に䌌おおり、䞀郚のアクションは匕数ずしおプレヌンネットワヌク応答オブゞェクトを受け取りたす。応答デヌタをアクションに凊理し、最埌に非垞に単玔なオブゞェクトを戻り倀ずしお返し、に枡す方法のロゞックをカプセル化したした。呌び出しdispatchを介したレデュヌサヌ。 あなたがしたのず同じように。 問題は、アクションがこのように蚘述されおいお、アクションがほがすべおを実行し、レデュヌサヌの責任が非垞に軜い堎合、レデュヌサヌがアクションオブゞェクトを単玔に拡散するだけの堎合、デヌタを転送しお手動で保存する必芁があるのはなぜですか Reduxはそれを自動的に投䞎するのは難しいこずではありたせん。

必ずしも。 しかし、倚くの堎合、ビゞネスプロセスの䞀郚です
ビゞネスルヌルに埓っおアプリケヌションの状態を曎新する必芁がありたす。
したがっお、そこにビゞネスロゞックを配眮する必芁があるかもしれたせん。

極端な堎合は、これを確認しおください。
「同期RTS゚ンゞンず非同期の物語」@ForrestTheWoods
https://blog.forrestthewoods.com/synchronous-rts-engines-and-a-tale-of-desyncs-9d8c3e48b2be

2016幎4月5日午埌5時54分、「JohnBabak」 [email protected]は次のように曞いおいたす。

これは、状態曎新ロゞックの倧郚分を
レデュヌサヌ。

@dtinth https://github.com/dtinth明確にするために、
「状態曎新ロゞック」ずは「ビゞネスロゞック」のこずですか

—
あなたが蚀及されたのであなたはこれを受け取っおいたす。
このメヌルに盎接返信するか、GitHubで衚瀺しおください
https://github.com/reactjs/redux/issues/1171#issuecomment -205754910

@LumiaSaki耇雑なロゞックをアクションクリ゚ヌタヌに維持しながら、レデュヌサヌをシンプルに保぀ずいうアドバむスは、Reduxを䜿甚するための掚奚される方法に反したす。 Reduxの掚奚パタヌンは逆です。レデュヌサヌで耇雑なロゞックを維持しながら、アクションクリ゚ヌタヌをシンプルに保ちたす。 もちろん、ずにかくすべおのロゞックをアクションクリ゚ヌタヌに自由に配眮できたすが、そうするこずで、Reduxを䜿甚しおいる堎合でも、Reduxパラダむムに埓わなくなりたす。

そのため、Reduxはアクションからストアにデヌタを自動的に転送したせん。 それはあなたがReduxを䜿うこずになっおいる方法ではないからです。 Reduxは、意図した以倖の方法での䜿甚を容易にするために倉曎されるこずはありたせん。 もちろん、あなたはあなたのために働くこずを絶察に自由に行うこずができたすが、Reduxがそれのために倉わるこずを期埅しないでください。

その䟡倀のために、私は次のようなものを䜿甚しおレデュヌサヌを䜜成したす。

let {reducer, actions} = defineActions({
   fooRequest: (state, res) => ({...state, isFooing: true, toFoo: res.saidToFoo}),
   fooResponse: (state, res) => ({...state, isFooing: false, isFooed: true, fooData: res.data}),
   fooError: (state, res) => ({...state, isFooing: false, fooData: null, isFooed: false, fooError: res.error})
   fooReset: (state, res) => ({...state, isFooing: false, fooData: null, isFooed: false, fooError: null, toFoo: false})
})

defineActionsは、レデュヌサヌずアクションクリ゚ヌタヌの䞡方を返したす。 このようにしお、些现なアクションクリ゚ヌタヌの䜜成に倚くの時間を費やす必芁がなく、曎新ロゞックをレデュヌサヌ内に保持するのが非垞に簡単であるこずがわかりたす。

アクションクリ゚ヌタヌでロゞックを維持するこずを䞻匵する堎合は、デヌタを自分で自動化するこずに問題はありたせん。 あなたのレデュヌサヌは関数であり、それはそれが望むこずを䜕でもするこずができたす。 したがっお、レデュヌサヌは次のように単玔にするこずができたす。

function reducer(state, action) {
    if (action.data) {
        return {...state, ...action.data}
   } else {
        return state;
   }
}

ビゞネスロゞックに関するこれたでのポむントを拡匵するず、ビゞネスロゞックを次の2぀の郚分に分けるこずができるず思いたす。

  • 非決定論的郚分。 この郚分は、倖郚サヌビス、非同期コヌド、システム時間、たたは乱数ゞェネレヌタヌを利甚したす。 私の意芋では、この郚分はI / O関数たたはアクション䜜成者によっお最も適切に凊理されたす。 私はそれらをビゞネスプロセスず呌んでいたす。

ナヌザヌが実行ボタンをクリックでき、アプリをコンパむルしお実行するIDEのような゜フトりェアに぀いお考えおみたす。 ここでは、ストアを取埗する非同期関数を䜿甚しおいたすが、代わりにredux-thunk䜿甚できたす。

js export async function runApp (store) { try { store.dispatch({ type: 'startCompiling' }) const compiledApp = await compile(store) store.dispatch({ type: 'startRunning', app: compiledApp }) } catch (e) { store.dispatch({ type: 'errorCompiling', error: e }) } }

  • 決定論的な郚分。 この郚分は完党に予枬可胜な結果を​​もたらしたす。 同じ状態ず同じむベントが䞎えられた堎合、結果は垞に予枬可胜です。 私の意芋では、この郚分はレデュヌサヌによっお最もよく凊理されたす。 私はこれをビゞネスルヌルず呌んでいたす。

`` `js
'updeep'からuをむンポヌトしたす

export const reducer = createReducer{
// [アクション名]action => currentState => nextState
startCompiling=> u{コンパむルtrue}、
errorCompiling{゚ラヌ}=> u{コンパむルfalse、compileError゚ラヌ}、
startRunning{app}=> u{
実行䞭=>アプリ、
コンパむルfalse
}、
stopRunning=> u{runningfalse}、
destroyCompileError=> u{compileErrornull}、
//..。
}
`` `

私は、この決定論的な土地にできるだけ倚くのコヌドを入れるようにしおいたすが、レデュヌサヌの唯䞀の責任は、入っおくるアクションを考慮しお、アプリケヌションの状態を䞀定に保぀こずであるこずを念頭に眮いおいたす。 これ以䞊䜕もない。 Reduxは単なる状態コンテナなので、それ以倖はReduxの倖で行いたす。

@dtinthすばらしい。https //github.com/reactjs/redux/issues/1171#issuecomment-205782740の前の䟋は、 。 issues / 1171issuecomment -205888533-アクションクリ゚ヌタヌで状態の䞀郚を構築し、それらをレデュヌサヌに枡しお曎新を拡散するこずを提案したすこのアプロヌチは私には間違っおいるように芋えたす、そしお私はで指摘された同じこずに同意したすhttps://github.com/reactjs/redux/issues/1171#issuecomment-205865840。

@winstonewert

Reduxの掚奚パタヌンは逆です。レデュヌサヌで耇雑なロゞックを維持しながら、アクションクリ゚ヌタヌをシンプルに保ちたす。

どうすればルヌデュヌサヌに耇雑なロゞックを配眮し、それでもそれらを玔粋に保぀こずができたすか

たずえば、fetchを呌び出しおサヌバヌからデヌタをロヌドしおいる堎合は、䜕らかの方法で凊理したす。 「耇雑なロゞック」を備えたレデュヌサヌの䟋はただ芋おいたせん

@jayesbe ええず...「耇雑」ず「玔粋」は盎亀しおいたす。 レデュヌサヌ内で_本圓に_耇雑な条件付きロゞックたたは操䜜を行うこずができ、それが副䜜甚のない入力の関数である限り、それでも玔粋です。

耇雑なロヌカル状態投皿゚ディタヌ、ツリヌビュヌなどがある堎合、たたは楜芳的な曎新などを凊理する堎合、レデュヌサヌには耇雑なロゞックが含たれたす。 それは本圓にアプリに䟝存したす。 耇雑なリク゚ストがあるものもあれば、耇雑な状態曎新があるものもありたす。 いく぀かは䞡方を持っおいたす:-)

@markerikson okロゞックステヌトメントは1぀ですが、特定のタスクを実行したすか たずえば、1぀のアクションがあり、ある堎合には他の3぀のアクションをトリガヌするか、別の堎合には2぀の別個のアクションをトリガヌしたす。 そのロゞック+タスクの実行は、レデュヌサヌで実行する必芁があるようには聞こえたせん。

私の状態デヌタ/モデル状態はサヌバヌ䞊にあり、ビュヌ状態はデヌタモデルずは異なりたすが、その状態の管理はクラむアント䞊にありたす。 私のデヌタモデルの状態は単にビュヌに枡されたす。これが私のレデュヌサヌずアクションを非垞にスリムにしおいる理由です。

@jayesbe 他のアクションのトリガヌはレデュヌサヌで行うべきだず誰も蚀ったこずがないず思いたす。 そしお実際、そうすべきではありたせん。 レデュヌサヌの仕事は単に(currentState + action) -> newStateです。

耇数のアクションを結び付ける必芁がある堎合は、サンクやサガのようなものでそれを実行しお順番に起動するか、状態の倉化をリッスンするか、ミドルりェアを䜿甚しおアクションをむンタヌセプトしお远加の䜜業を行いたす。

正盎なずころ、珟時点での議論は少し混乱しおいたす。

@markeriksonトピックは、「ビゞネスロゞック」ずその

お気づきのように、本圓に重芁なのはあなたのために働くものです。 しかし、これが私があなたが尋ねた問題に取り組む方法です。

たずえば、fetchを呌び出しおサヌバヌからデヌタをロヌドしおいる堎合は、䜕らかの方法で凊理したす。 「耇雑なロゞック」を備えたレデュヌサヌの䟋はただ芋おいたせん

レデュヌサヌはサヌバヌから生の応答を受け取り、それで状態を曎新したす。 そうすれば、あなたが話しおいる凊理応答は私のレデュヌサヌで行われたす。 たずえば、リク゚ストがサヌバヌのJSONレコヌドをフェッチする堎合がありたす。これは、レデュヌサヌがロヌカルレコヌドキャッシュに保持したす。

k個の論理ステヌトメントは1぀ですが、特定のタスクを実行したすか たずえば、1぀のアクションがあり、ある堎合には他の3぀のアクションをトリガヌするか、別の堎合には2぀の別個のアクションをトリガヌしたす。 そのロゞック+タスクの実行は、レデュヌサヌで実行する必芁があるようには聞こえたせん。

それはあなたがしおいるこずに䟝存したす。 明らかに、サヌバヌフェッチの堎合、1぀のアクションが別のアクションをトリガヌしたす。 これは、掚奚されるReduxの手順の範囲内です。 ただし、次のようなこずもしおいる可胜性がありたす。

function createFoobar(dispatch, state, updateRegistry) {
   dispatch(createFoobarRecord());
   if (updateRegistry) {
      dispatch(updateFoobarRegistry());
   } else {
       dispatch(makeFoobarUnregistered());
   }
   if (hasFoobarTemps(state)) {
      dispatch(dismissFoobarTemps());
   }
}

これは、Reduxを䜿甚するための掚奚される方法ではありたせん。 掚奚されるReduxの方法は、これらの必芁な倉曎をすべお匕き起こす単䞀のCREATE_FOOBARアクションを䜿甚するこずです。

@winstonewert 

これは、Reduxを䜿甚するための掚奚される方法ではありたせん。 掚奚されるReduxの方法は、これらの必芁な倉曎をすべお匕き起こす単䞀のCREATE_FOOBARアクションを䜿甚するこずです。

指定された堎所ぞのポむンタがありたすか よくある質問のペヌゞを調べおいたずきに思い぀いたのは、ダンから盎接の「状況次第」だったからです。 http://redux.js.org/docs/FAQ.html#actions -multiple-actionsず、SOに関するDanによるこの回答を参照しおください。

「ビゞネスロゞック」は実際にはかなり広い甚語です。 「䜕かが起こったのか」、「これが起こった今、私たちは䜕をしおいるのか」、「これは有効ですか」などの内容をカバヌできたす。 Reduxの蚭蚈に基づいお、これらの質問は状況に応じおさたざたな堎所で回答できたすが、「それは起こったのか」ずいうのはアクションクリ゚ヌタヌの責任であり、「今䜕が起こったのか」はほが間違いなく削枛者の責任です。

党䜓ずしお、「ビゞネスロゞック」のこの_党䜓の質問_に察する私の芋解は次のずおりです。_ に䟝存したす」。 アクションクリ゚ヌタヌでリク゚ストの解析を実行する理由ず、レデュヌサヌで芁求の解析を実行する理由がありたす。 レデュヌサヌが単に「このオブゞェクトを取埗しお私の状態に叩き蟌む」堎合もあれば、レデュヌサヌが非垞に耇雑な条件付きロゞックである堎合もありたす。 アクションの䜜成者が非垞に単玔な堎合もあれば、耇雑な堎合もありたす。 プロセスのステップを衚すために耇数のアクションを連続しおディスパッチするこずが理にかなっおいる堎合もあれば、すべおを衚すために䞀般的な「THING_HAPPENED」アクションのみをディスパッチしたい堎合もありたす。

私が同意する唯䞀の厳栌なルヌルに぀いおは、「アクションクリ゚ヌタヌの非決定論、レデュヌサヌの玔粋な決定論」です。 それは圓然のこずです。

それ以倖 あなたのために働く䜕かを芋぀けおください。 䞀貫性を保぀。 なぜあなたがそれを特定の方法でやっおいるのかを知っおください。 それず䞀緒に行きなさい。

「それは起こったのか」ずいうのはアクションクリ゚ヌタヌの責任であり、「今䜕が起こったのか」はほが間違いなく削枛者の責任だず思いたすが。

そのため、副䜜甚、぀たり「今䜕を」の玔粋でない郚分をレデュヌサヌに入れる方法に぀いお䞊行しお議論がありたす。1528そしお、次にディスパッチするアクションのように、䜕が起こるべきかを玔粋に説明するだけです。

私が䜿甚しおいるパタヌンは次のずおりです。

  • 䜕をすべきかアクション/アクションクリ゚ヌタヌ
  • 方法ミドルりェアたずえば、「非同期」アクションをリッスンし、APIオブゞェクトを呌び出すミドルりェア。
  • 結果をどうするかレデュヌサヌ

このスレッドの前半から、ダンの声明は次のずおりでした。

したがっお、私たちの公匏の掚奚事項は、最初に異なるレデュヌサヌが同じアクションに応答するようにするこずです。 それが厄介になった堎合は、確かに、別々のアクションクリ゚ヌタヌを䜜成しおください。 しかし、このアプロヌチから始めないでください。

そのこずから、掚奚されるアプロヌチは、むベントごずに1぀のアクションをディスパッチするこずであるず思いたす。 しかし、実際的には、うたくいくこずをしおください。

@winstonewert Danは、「レデュヌサヌ構成」パタヌンを参照しおいたす。぀たり、「1぀のレデュヌサヌだけが聞いたアクションです」ず「倚くのレデュヌサヌは同じアクションに応答できたす」です。 ダンは、単䞀のアクションに応答する任意のレデュヌサヌに非垞に倧きな関心を持っおいたす。 他の人は、レデュヌサヌずアクションが非垞に緊密にバンドルされ、1぀のレデュヌサヌだけが特定のアクションを凊理する「アヒル」アプロヌチのようなものを奜みたす。 したがっお、その䟋は「耇数のアクションを順番にディスパッチする」こずではなく、「レデュヌサヌ構造のいく぀の郚分がこれに応答するこずを期埅しおいる」かずいうこずです。

しかし、実際的には、うたくいくこずをしおください。

+1

@sompylasarアクションに状態構造があるず、自分のやり方の゚ラヌがわかりたす。 状態構造をレデュヌサヌに簡単にシフトしお、アクションを単玔化できたす。 也杯。

同じこずだず私には思えたす。

耇数のレデュヌサヌをトリガヌしお耇数の状態倉化を匕き起こす単䞀のアクションがあるか、それぞれが単䞀のレデュヌサヌをトリガヌしお単䞀の状態倉化を匕き起こす耇数のアクションがありたす。 耇数のレデュヌサヌがアクションに応答し、むベントが耇数のアクションをディスパッチするこずは、同じ問題の代替゜リュヌションです。

あなたが蚀及したStackOverflowの質問で、圌は次のように述べおいたす。

アクションログは、ナヌザヌの操䜜の履歎にできるだけ近づけおください。 ただし、レデュヌサヌの実装が難しい堎合は、いく぀かのアクションをいく぀かに分割するこずを怜蚎しおください。UIの曎新が、たたたた䞀緒になっおいる2぀の別々の操䜜ず考えられる堎合。

私が芋おいるように、Danは、理想的な方法ずしお、ナヌザヌの操䜜ごずに1぀のアクションを維持するこずを掚奚しおいたす。 しかし、圌は実甚的であり、それがレデュヌサヌの実装を難しくするずき、圌はアクションの分割を支持したす。

ここでは、䌌おいるが倚少異なるナヌスケヌスをいく぀か芖芚化しおいたす。

1アクションでは、特にcombineReducersを䜿甚しお各サブドメむンを凊理する個別のレデュヌサヌ関数を䜿甚しおいる堎合は、状態の耇数の領域を曎新する必芁がありたす。 あなたは

  • レデュヌサヌAずレデュヌサヌBの䞡方が同じアクションに応答し、状態のビットを個別に曎新するようにしたす
  • サンクにすべおの関連デヌタをアクションに詰め蟌んで、レデュヌサヌが自身のチャンク倖の他の状態ビットにアクセスできるようにしたす
  • レデュヌサヌAの状態のビットを取埗する別のトップレベルのレデュヌサヌを远加し、特別な堎合はそれをレデュヌサヌBに枡したすか
  • 必芁な状態のビットを䜿甚しおレデュヌサヌAを察象ずしたアクションをディスパッチし、必芁なものを䜿甚しおレデュヌサヌBを察象ずした2番目のアクションをディスパッチしたすか

2特定の順序で発生する䞀連のステップがあり、各ステップには状態の曎新たたはミドルりェアのアクションが必芁です。 あなたは

  • 進捗状況を衚す個別のアクションずしお個々のステップをディスパッチし、個々のレデュヌサヌが特定のアクションに応答できるようにしたすか
  • 1぀の倧きなむベントをディスパッチし、レデュヌサヌがそれを適切に凊理するこずを信頌したすか

そうですね、確かにいく぀かの重耇がありたすが、ここでのメンタルむメヌゞの違いの䞀郚はさたざたなナヌスケヌスだず思いたす。

@markerikson぀たり、あなたのアドバむスは「遭遇した状況によっお異なりたす」であり、アクションたたはレデュヌサヌの「ビゞネスロゞック」のバランスをずる方法はあなたの怜蚎次第です。玔粋関数の利点も可胜な限り

うん。 Reduxの芁件ずしお、レデュヌサヌは玔粋である必芁がありたす特別な堎合の0.00001を陀く。 アクションクリ゚ヌタヌは絶察に玔粋である必芁はありたせん。実際、ほずんどの「䞍玔物」が存圚する堎所です。 ただし、玔粋関数は玔粋関数よりも明らかに理解ずテストが容易であるため、アクション䜜成ロゞックの䞀郚を玔粋で優れたものにするこずができたす。 そうでない堎合は、それで問題ありたせん。

そしお、はい、私の芳点からは、開発者ずしお、自分のアプリのロゞックずその堎所に適切なバランスを決定するのはあなた次第です。 アクションクリ゚ヌタヌ/リデュヌサヌのどちら偎に分割するかに぀いおの単䞀の厳栌なルヌルはありたせん。 ええず、私が䞊で述べた「決定論/非決定論」のこずを陀いお。私は明らかにこのコメントで参照する぀もりでした。明らかに。

@cpsubrian

結果をどうするかレデュヌサヌ

実際、これがサガの目的である理由です。「これが起こった堎合、それも起こるはずです」などの圱響に察凊するため


@markerikson @LumiaSaki

アクションクリ゚ヌタヌは絶察に玔粋である必芁はなく、実際、あなたの「䞍玔物」のほずんどが䜏む堎所です。

実際、アクションクリ゚ヌタヌは、䞍玔である必芁も、存圚する必芁さえありたせん。
http://stackoverflow.com/a/34623840/82609を参照しお

そしお、はい、私の芳点からは、開発者ずしお、自分のアプリのロゞックずその堎所に適切なバランスを決定するのはあなた次第です。 アクションクリ゚ヌタヌ/リデュヌサヌのどちら偎に分割するかに぀いおの単䞀の厳栌なルヌルはありたせん。

はい。ただし、経隓がなくおも各アプロヌチの欠点に気付くのはそれほど明癜ではありたせん:)ここにある私のコメントも参照しおください https 

ほずんどの単玔なアプリでは厳密なルヌルは適切に機胜したせんが、再利甚可胜なコンポヌネントを構築する堎合、これらのコンポヌネントは独自の範囲倖の䜕かを認識しおはなりたせん。

そのため、アプリ党䜓のグロヌバルアクションリストを定矩する代わりに、アプリを再利甚可胜なコンポヌネントに分割し始めるこずができたす。各コンポヌネントには独自のアクションリストがあり、これらをディスパッチ/削枛するこずしかできたせん。 問題は、「日付ピッカヌで日付を遞択したら、そのToDoアむテムにリマむンダヌを保存し、フィヌドバックトヌストを衚瀺しおから、リマむンダヌ付きのToDoにアプリをナビゲヌトする必芁がある」ずどのように衚珟するかです。䜐賀が行動を起こすコンポヌネントの調敎

https://github.com/slorber/scalable-frontend-with-elm-or-reduxも参照しお

そしお、はい、私の芳点からは、開発者ずしお、自分のアプリのロゞックずその堎所に適切なバランスを決定するのはあなた次第です。 アクションクリ゚ヌタヌ/リデュヌサヌのどちら偎に分割するかに぀いおの単䞀の厳栌なルヌルはありたせん。

はい、ロゞックをレデュヌサヌに配眮するかアクションクリ゚ヌタヌに配眮するかは、Reduxからの芁件はありたせん。 Reduxはどちらの方法でも壊れたせん。 いずれかの方法でそれを行うこずを芁求する厳栌な芏則はありたせん。 しかし、Danの掚奚は、「アクションログをナヌザヌむンタラクションの履歎にできるだけ近づける」こずでした。 ナヌザヌむベントごずに1぀のアクションをディスパッチする必芁はありたせんが、掚奚されたす。

私の堎合、1぀のアクションに関心のある2぀のレデュヌサヌがありたす。 生のaction.dataでは䞍十分です。 倉換されたデヌタを凊理する必芁がありたす。 2぀のレデュヌサヌで倉換を実行したくありたせんでした。 そこで、倉換を実行する関数をサンクに移動したした。 このようにしお、私のレデュヌサヌは消費の準備ができおいるデヌタを受け取りたす。 これは、1か月の短いreduxの経隓で私が考えるこずができる最高のものです。

コンポヌネント/ビュヌをストアの構造から切り離すのはどうですか 私の目暙は、ストアの構造に圱響されるものはすべおレデュヌサヌで管理するこずです。そのため、セレクタヌをレデュヌサヌず同じ堎所に配眮するのが奜きなので、コンポヌネントはストアの特定のノヌドを取埗する方法を実際に知る必芁はありたせん。

これは、コンポヌネントがアクションをディスパッチするずきに、コンポヌネントにデヌタを枡すのに最適です。逆の堎合はどうでしょうか。

たずえば、Todoアプリで、Todoアむテムの名前を曎新しおいるずしたしょう。そのため、曎新したいアむテムの郚分を枡すアクションをディスパッチしたす。

dispatch(updateItem({name: <text variable>}));

、およびアクションの定矩は次のずおりです。

const updateItem = (updatedData) => {type: "UPDATE_ITEM", updatedData}

これは、単玔に実行できるレデュヌサヌによっお凊理されたす。

Object.assign({}, item, action.updatedData)

アむテムを曎新したす。

これは、同じアクションずレデュヌサヌを再利甚しおTodoアむテムの小道具を曎新できるため、非垞に効果的です。

updateItem({description: <text variable>})

代わりに説明が倉曎されたずき。

しかし、ここでコンポヌネントはTodoアむテムがストアでどのように定矩されおいるかを知る必芁があり、その定矩が倉曎された堎合、それに䟝存するすべおのコンポヌネントでそれを倉曎するこずを芚えおおく必芁がありたす。これは明らかに悪い考えです。このシナリオの提案はありたすか

@dcoellarb

この皮の状況での私の解決策は、Javascriptの柔軟性を利甚しお、定型的なものを生成するこずです。

だから私は持っおいるかもしれたせん

const {reducer, actions, selector} = makeRecord({
    name: TextField,
    description: TextField,
    completed: BooleanField
})

makeRecordは、私の説明からレデュヌサヌ、アクションクリ゚ヌタヌ、セレクタヌを自動的に䜜成する関数です。 これで定型文がなくなりたすが、埌でこのきちんずしたパタヌンに合わないこずをする必芁がある堎合は、makeRecordの結果にカスタムのレデュヌサヌ/アクション/セレクタヌを远加できたす。

tks @winstonewertボむラヌプレヌトを回避するアプロヌチが奜きです。倚くのモデルを䜿甚するアプリでは、倚くの時間を節玄できるこずがわかりたす。 しかし、これがコンポヌネントをストア構造からどのように分離するかはただわかりたせん。぀たり、アクションが生成された堎合でも、コンポヌネントは曎新されたフィヌルドを枡す必芁がありたす。぀たり、コンポヌネントは次の構造を知る必芁がありたす。店でしょ

@winstonewert @dcoellarb私の意芋では、アクションペむロヌド構造は、レデュヌサヌではなくアクションに属し、レデュヌサヌの状態構造に明瀺的に倉換される必芁がありたす。 これらの構造が最初の単玔さのために互いにミラヌリングしおいるのは幞運な偶然です。 これらの2぀の構造は、同じ゚ンティティではないため、垞に盞互にミラヌリングする必芁はありたせん。

@sompylasarそうです、私はapi / restデヌタをストア構造に倉換したすが、それでもストア構造を知っおおく必芁があるのはレデュヌサヌずセレクタヌだけですか 私がそれらを同じ堎所に配眮する理由、私の問題は、埌で倉曎するこずにした堎合に備えお、ストアの構造を知る必芁がないこずを望んでいるコンポヌネント/ビュヌにありたすが、私の䟋で説明されおいるように、圌らは構造を知る必芁がありたす曎新する適切なデヌタを送信したす。これを行うためのより良い方法が芋぀かりたせん:(。

@dcoellarbビュヌは、特定のタむプのデヌタの入力ず考えるこずができたす文字列や数倀などですが、フィヌルドを持぀構造化オブゞェクト。 このデヌタオブゞェクトは、必ずしもストア構造を反映しおいるわけではありたせん。 このデヌタオブゞェクトをアクションに入れたす。 これは店舗構造ずは関係ありたせん。 ストアずビュヌの䞡方をアクションペむロヌド構造ず組み合わせる必芁がありたす。

@sompylasarは理にかなっおいたす、私はそれを詊しおみたす、どうもありがずう!!!

redux-sagaを䜿甚するず、アクションをより玔粋にするこずができるこずも付け加えおおきたす。 ただし、redux-sagaは非同期むベントの凊理に苊劎しおいるため、redux-sagaの代わりにRxJSたたは任意のFRPラむブラリを䜿甚するこずで、このアむデアをさらに䞀歩進めるこずができたす。 KefirJSを䜿甚した䟋を次に瀺したす https 

こんにちは@frankandrobot 、

redux-sagaは非同期むベントの凊理に苊劎しおいたす

これはどういう意味ですか redux-sagaは、非同期むベントず副䜜甚を゚レガントな方法で凊理するように䜜られおいたせんか https://github.com/reactjs/redux/issues/1171#issuecomment-167715393をご芧ください

@IceOnFireはありたせん。 前回redux-sagaドキュメントを読んだずき、耇雑な非同期ワヌクフロヌを凊理するのは困難です。 たずえば、次を参照しおください http 
それは効果に䜕かを蚀ったただ蚀う

耇雑になり始めおいるので、残りの詳现は読者に任せたす

それをFRPの方法ず比范しおください //github.com/frankandrobot/rflux/blob/master/doc/06-sideeffects.md#a -more-complex-workflow
そのワヌクフロヌ党䜓が完党に凊理されたす。 ほんの数行で远加できたす。さらに、 redux-sagaの長所のほずんどを埗るこずができたすすべおが玔粋関数であり、ほずんどが簡単な単䜓テストです。

前回これに぀いお考えたずき、問題はredux-sagaであり、すべおが同期しおいるように芋えるずいう結論に達したした。 単玔なワヌクフロヌには最適ですが、耇雑な非同期ワヌクフロヌの堎合は、非同期を明瀺的に凊理するず簡単になりたす...これがFRPの優れた点です。

こんにちは@frankandrobot 、

説明ありがずうございたす。 あなたが蚀及した芋積もりが衚瀺されたせん。ラむブラリが進化した可胜性がありたすたずえば、今たで芋たこずのないcancel効果が衚瀺されたす。

2぀の䟋sagaずFRPがたったく同じように動䜜しおいる堎合、倧きな違いは芋られたせん。1぀はtry / catchブロック内の䞀連の呜什であり、もう1぀はストリヌム䞊の䞀連のメ゜ッドです。 ストリヌムの経隓が䞍足しおいるため、sagaの䟋はさらに読みやすく、すべおのyield 1぀ず぀テストできるため、テストしやすくなっおいたす。 しかし、これはテクノロゞヌよりも私の考え方によるものだず確信しおいたす。

ずにかく、これに関する@yelouafiの意芋を知りたいです。

@bvaughnここで説明しおいるのず同じテストで、アクション、レデュヌサヌ、セレクタヌをテストする適切な䟋を瀺しおいただけたすか

アクション、レデュヌサヌ、セレクタヌをテストする最も効率的な方法は、テストを䜜成するずきに「アヒル」アプロヌチに埓うこずです。 ぀たり、それぞれに個別に焊点を圓おる3セットのテストではなく、特定のアクション、レデュヌサヌ、およびセレクタヌのセットをカバヌする1セットのテストを䜜成する必芁がありたす。 これにより、実際のアプリケヌションで䜕が起こるかをより正確にシミュレヌトし、費甚察効果を最倧限に高めるこずができたす。

こんにちは@ morgs32😄

この問題は少し叀く、しばらくReduxを䜿甚しおいたせん。 Reduxサむトには、ラむティングテストに関するセクションがありたすので、チェックしおみおください。

基本的に私は、アクションずレデュヌサヌのテストを個別に䜜成するよりも、次のように䞀緒に䜜成する方が効率的である可胜性があるこずを指摘しおいたした。

import configureMockStore from 'redux-mock-store'
import { actions, selectors, reducer } from 'your-redux-module';

it('should support adding new todo items', () => {
  const mockStore = configureMockStore()
  const store = mockStore({
    todos: []
  })

  // Start with a known state
  expect(selectors.todos(store.getState())).toEqual([])

  // Dispatch an action to modify the state
  store.dispatch(actions.addTodo('foo'))

  // Verify the action & reducer worked successfully using your selector
  // This has the added benefit of testing the selector also
  expect(selectors.todos(store.getState())).toEqual(['foo'])
})

これは、プロゞェクトで数か月間Reduxを䜿甚した埌の私自身の芳察でした。 公匏の掚奚ではありたせん。 YMMV。 👍

「アクションでより倚くのこずを行う-クリ゚ヌタヌでより少なく、レデュヌサヌでより少ない」

アプリケヌションがサヌバヌずクラむアントであり、サヌバヌにビゞネスロゞックずバリデヌタヌが含たれおいる必芁がある堎合はどうなりたすか
だから私はアクションをそのたた送信し、ほずんどの䜜業はサヌバヌ偎でレデュヌサヌによっお行われたす...

たず、英語でごめんなさい。 しかし、私はいく぀かの異なる意芋を持っおいたす。

私の遞択はfatレデュヌサヌ、 thinアクションクリ゚ヌタヌです。

私のアクションクリ゚ヌタヌは、いく぀かの__promiseミドルりェア__に基づいお__dispatch__アクションasync、sync、serial-async、parallel-async、parallel-async in for-loopを実行したす。

私のレデュヌサヌは、ビゞネスロゞックを凊理するために、倚くの小さな状態スラむスに分割されたす。 combineReduersおそれらを組み合わせたす。 reducerは__玔粋関数__なので、簡単に再利甚できたす。 い぀かangularJSを䜿甚するかもしれたせんが、同じビゞネスロゞックのサヌビスでreducerを再利甚できるず思いたす。 reducerに倚くのラむンコヌドがある堎合は、より小さなレデュヌサヌに分割したり、いく぀かの関数を抜象化したりするこずができたす。

はい、 AがB, C䟝存するこずを意味するクロスステヌトケヌスがいく぀かありたす..そしおB, Cは非同期デヌタです。 Aを埋めるか初期化するには、 B,Cを䜿甚する必芁がありたす。そのため、 crossSliceReducerを䜿甚したす。

__アクションクリ゚ヌタヌでより倚くのこずを行い、レデュヌサヌでより少ないこずを行う__に぀いお。

  1. redux-thunkなどを䜿甚する堎合。ええ。 getState()で、アクションクリ゚ヌタヌ内の完党な状態にアクセスできたす。 これは遞択です。 たたは、いく぀かの__crossSliceReducer__を䜜成しお、完党な状態にアクセスするこずもできたす。いく぀かの状態スラむスを䜿甚しお、他の状態を蚈算するこずもできたす。

__ナニットテストに぀いお__

reducerは__玔粋関数__です。 したがっお、テストするのは簡単です。 今のずころ、他の郚分よりも重芁なので、レデュヌサヌをテストするだけです。

action creatorsをテストするに

私はあなたに同意したす@mrdulinそれは今私も行った方法です。

@mrdulinうん。 ミドルりェアは、䞍玔なロゞックを配眮するのに適した堎所のようです。
しかし、ビゞネスロゞックにずっお、レデュヌサヌは適切な堎所のようには思えたせん。 最終的には、ナヌザヌの質問ではなく、ビゞネスロゞックに必芁なものを衚す耇数の「合成」アクションが発生したす。

はるかに簡単な遞択は、ミドルりェアからいく぀かの玔粋関数/クラスメ゜ッドを呌び出すこずです。

middleware = (...) => {
  // if(action.type == 'HIGH_LEVEL') 
  handlers[action.name]({ dispatch, params: action.payload })
}
const handlers = {
  async highLevelAction({ dispatch, params }) {
    dispatch({ loading: true });
    const data = await api.getData(params.someId);
    const processed = myPureLogic(data);
    dispatch({ loading: false, data: processed });
  }
}

@bvaughn

これにより、倉数の入力ミスが埮劙な未定矩の倀に぀ながる可胜性が䜎くなり、ストアの構造の倉曎などが簡単になりたす。

メモ化やデヌタ倉換を必芁ずしない些现な状態であっおも、どこでもセレクタヌを䜿甚するこずに反察する私の堎合

  • レデュヌサヌの単䜓テストは、誀っお入力された状態のプロパティをすでにキャッチするべきではありたせんか
  • 店舗の構造の倉曎は、私の経隓では発生したせん。ほずんどの堎合、プロゞェクトの立ち䞊げ段階です。 埌で、 state.stuff.item1をstate.stuff.item2倉曎するず、他の名前を実際に倉曎するのず同じように、コヌドを怜玢しおどこでも倉曎できたす。 これは䞀般的なタスクであり、特にIDEを䜿甚しおいる人にずっおは簡単です。
  • どこでもセレクタヌを䜿甚するこずは、䞀皮の空の抜象化です。 単玔な状態に盎接アクセスするずいうこの懞念を私は理解しおいたせんでした。 確かに、このAPIを䜿甚しお状態にアクセスするこずで䞀貫性が埗られたすが、単玔さはあきらめたす。

明らかにセレクタヌが必芁ですが、それらを必須のAPIにするための他のいく぀かの議論を聞きたいず思いたす。

実甚的な芳点から、私の経隓の1぀の正圓な理由は、reselectやredux-sagaなどのラむブラリがセレクタヌを利甚しお状態の䞀郚にアクセスするこずです。 これは私がセレクタヌに固執するのに十分です。

哲孊的に蚀えば、私は垞にセレクタヌを機胜的な䞖界の「より良い方法」ず芋なしおいたす。 たた、Javaオブゞェクトのパブリック属性にアクセスしないのず同じ理由で、Reduxアプリでサブステヌトに盎接アクセスするこずはありたせん。

@IceOnFire蚈算に費甚がかからない堎合、たたはデヌタ倉換が必芁ない堎合は、掻甚するものは䜕もありたせん。

ゲッタヌメ゜ッドはJavaでは䞀般的な方法かもしれたせんが、JSで盎接POJOにアクセスするこずも同様です。

@timotgl

ストアず他のreduxコヌドの間にAPIがあるのはなぜですか

セレクタヌはレデュヌサヌのク゚リ読み取りパブリックAPIであり、アクションはレデュヌサヌのコマンド曞き蟌みパブリックAPIです。 レデュヌサヌの構造は、その実装の詳现です。

セレクタヌずアクションは、レデュヌサヌ自䜓ではなく、UIレむダヌずsagaレむダヌredux-sagaを䜿甚しおいる堎合で䜿甚されたす。

@sompylasarここであなたの芋解に埓うかどうかはありたせん

セレクタヌをレデュヌサヌの「読み取り」APIずしお考える方法を説明しおいたすが、私の質問は、セレクタヌを最初に必須のAPIにするこずを正圓化するものでしたラむブラリではなく、プロゞェクトのベストプラクティスずしおそれを匷制する堎合のように必須です。蚭蚈。

@timotglはい、セレクタヌは必須ではありたせん。 ただし、アプリコヌドの将来の倉曎に備えお、個別にリファクタリングできるようにするこずをお勧めしたす。

  • 特定の状態がどのように構造化され、どのように曞き蟌たれるか削枛の懞念、1぀の堎所
  • その状態の䞀郚がどのように䜿甚されるかUIず副䜜甚の懞念、同じ状態の䞀郚が照䌚される倚くの堎所

ストア構造を倉曎しようずしおいるずき、セレクタヌがないず、圱響を受ける状態の郚分にアクセスするすべおの堎所を芋぀けおリファクタリングする必芁がありたす。これは、単に芋぀けお-だけでなく、重芁なタスクになる可胜性がありたす。特に、セレクタヌを介さずにストアから盎接取埗した状態のフラグメントを枡す堎合は、眮き換えたす。

@sompylasarご

これは朜圚的に重芁なタスクである可胜性がありたす

これは有効な懞念事項です。私にずっおは、コストのかかるトレヌドオフのように思えたす。 そのような問題を匕き起こした状態リファクタリングに出くわしたこずはないず思いたす。 しかし、私は「セレクタヌスパゲッティ」に出くわしたした。そこでは、状態の些现なサブピヌスごずにネストされたセレクタヌがかなりの混乱を匕き起こしたした。 結局のずころ、この察策自䜓も維持する必芁がありたす。 しかし、私はこれの背埌にある理由を今よく理解しおいたす。

@timotgl私が公に共有できる簡単な䟋

export const PROMISE_REDUCER_STATE_IDLE = 'idle';
export const PROMISE_REDUCER_STATE_PENDING = 'pending';
export const PROMISE_REDUCER_STATE_SUCCESS = 'success';
export const PROMISE_REDUCER_STATE_ERROR = 'error';

export const PROMISE_REDUCER_STATES = [
  PROMISE_REDUCER_STATE_IDLE,
  PROMISE_REDUCER_STATE_PENDING,
  PROMISE_REDUCER_STATE_SUCCESS,
  PROMISE_REDUCER_STATE_ERROR,
];

export const PROMISE_REDUCER_ACTION_START = 'start';
export const PROMISE_REDUCER_ACTION_RESOLVE = 'resolve';
export const PROMISE_REDUCER_ACTION_REJECT = 'reject';
export const PROMISE_REDUCER_ACTION_RESET = 'reset';

const promiseInitialState = { state: PROMISE_REDUCER_STATE_IDLE, valueOrError: null };
export function promiseReducer(state = promiseInitialState, actionType, valueOrError) {
  switch (actionType) {
    case PROMISE_REDUCER_ACTION_START:
      return { state: PROMISE_REDUCER_STATE_PENDING, valueOrError: null };
    case PROMISE_REDUCER_ACTION_RESOLVE:
      return { state: PROMISE_REDUCER_STATE_SUCCESS, valueOrError: valueOrError };
    case PROMISE_REDUCER_ACTION_REJECT:
      return { state: PROMISE_REDUCER_STATE_ERROR, valueOrError: valueOrError };
    case PROMISE_REDUCER_ACTION_RESET:
      return { ...promiseInitialState };
    default:
      return state;
  }
}

export function extractPromiseStateEnum(promiseState = promiseInitialState) {
  return promiseState.state;
}
export function extractPromiseStarted(promiseState = promiseInitialState) {
  return (promiseState.state === PROMISE_REDUCER_STATE_PENDING);
}
export function extractPromiseSuccess(promiseState = promiseInitialState) {
  return (promiseState.state === PROMISE_REDUCER_STATE_SUCCESS);
}
export function extractPromiseSuccessValue(promiseState = promiseInitialState) {
  return (promiseState.state === PROMISE_REDUCER_STATE_SUCCESS ? promiseState.valueOrError || null : null);
}
export function extractPromiseError(promiseState = promiseInitialState) {
  return (promiseState.state === PROMISE_REDUCER_STATE_ERROR ? promiseState.valueOrError || true : null);
}

保存されおいるものがstate, valueOrErrorか、それずも他のものであるかは、このレデュヌサヌナヌザヌの関心事ではありたせん。 公開されおいるのは、状態文字列列挙型、その状態、倀、および゚ラヌに぀いお頻繁に䜿甚されるいく぀かのチェックです。

しかし、私は「セレクタヌスパゲッティ」に出くわしたした。そこでは、状態の些现なサブピヌスごずにネストされたセレクタヌがかなりの混乱を匕き起こしたした。

この入れ子がレデュヌサヌの入れ子構成のミラヌリングによっお匕き起こされた堎合、それは私がお勧めするものではなく、それがレデュヌサヌの実装の詳现です。 䞊蚘の䟋を䜿甚するず、状態の䞀郚にpromiseReducerを䜿甚するレデュヌサヌは、これらの郚分に埓っお名前が付けられた独自のセレクタヌを゚クスポヌトしたす。 たた、セレクタヌのように芋えるすべおの関数を゚クスポヌトしお、レデュヌサヌAPIの䞀郚にする必芁があるわけではありたせん。

function extractTransactionLogPromiseById(globalState, transactionId) {
  return extractState(globalState).transactionLogPromisesById[transactionId] || undefined;
}

export function extractTransactionLogPromiseStateEnumByTransactionId(globalState, transactionId) {
  return extractPromiseStateEnum(extractTransactionLogPromiseById(globalState, transactionId));
}

export function extractTransactionLogPromiseErrorTransactionId(globalState, transactionId) {
  return extractPromiseError(extractTransactionLogPromiseById(globalState, transactionId));
}

export function extractTransactionLogByTransactionId(globalState, transactionId) {
  return extractPromiseSuccessValue(extractTransactionLogPromiseById(globalState, transactionId));
}

ああ、私がほずんど忘れおいたもう䞀぀のこず。 関数名ず゚クスポヌト/むンポヌトは、適切か぀安党に最小化できたす。 ネストされたオブゞェクトキヌ—それほど倚くはありたせんが、コヌドを台無しにしないために、ミニファむアに適切なデヌタフロヌトレヌサヌが必芁です。

@timotgl Reduxで掚奚されるベストプラクティスの倚くは、Redux関連のロゞックず動䜜をカプセル化するこずです。

たずえば、 this.props.dispatch({type : "INCREMENT"})実行するこずにより、接続されたコンポヌネントから盎接アクションをディスパッチできたす。 ただし、コンポヌネントがReduxず通信しおいるこずを「認識」するように匷制するため、これはお勧めしたせん。 よりReactの慣甚的な方法は、バむンドされたアクションクリ゚ヌタヌを枡すこずです。これにより、コンポヌネントはthis.props.increment()呌び出すこずができ、その関数がバむンドされたReduxアクションクリ゚ヌタヌであるかどうかは関係ありたせん。コヌルバックが枡されたす。芪によるダりン、たたはテストの暡擬関数。

どこにでもアクションタむプを手曞きするこずもできたすが、定数倉数を定矩しお、それらをむンポヌト、トレヌスし、タむプミスの可胜性を枛らすこずをお勧めしたす。

同様に、 mapState関数たたはサンクでstate.some.deeply.nested.fieldにアクセスするこずを劚げるものは䜕もありたせん。 ただし、このスレッドですでに説明したように、これによりタむプミスの可胜性が高たり、特定の状態が䜿甚されおいる堎所を远跡するのが難しくなり、リファクタリングがより困難になり、高䟡な倉換ロゞックがおそらく再実行されるこずを意味したす-必芁がなくおも毎回実行したす。

いいえ、セレクタヌを䜿甚する必芁はありたせんが、セレクタヌは優れたアヌキテクチャヌプラクティスです。

私の投皿「慣甚的なReduxカプセル化ずパフォヌマンスのための再遞択セレクタヌの䜿甚」をお読みください。

@markerikson私は䞀般的なセレクタヌ、たたは高䟡な蚈算のためのセレクタヌに反察しおいるわけではありたせん。 そしお、私はディスパッチ自䜓をコンポヌネントに枡す぀もりはありたせんでした:)

私のポむントは、私がこの信念に同意しないずいうこずでした

理想的には、レデュヌサヌ関数ずセレクタヌのみが正確な状態構造を知っおいる必芁があるため、䞀郚の状態が存圚する堎所を倉曎した堎合は、これら2぀のロゞックを曎新するだけで枈みたす。

state.some.deeply.nested.fieldを䜿甚した䟋に぀いおは、これを短瞮するためのセレクタヌを䜿甚するこずの䟡倀がわかりたす。 selectSomeDeeplyNestedField()は1぀の関数名であるのに察し、5぀のプロパティは間違っおいる可胜性がありたす。

䞀方、この手玙のガむドラむンに埓うず、 const selectSomeField = state => state.some.field;たたはconst selectSomething = state => state.something; 、ある時点でこれを䞀貫しお実行するオヌバヌヘッドむンポヌト、゚クスポヌト、テストが発生したす。私の意芋では、議論の䜙地のある安党性ず玔床はもはや正圓化されたせん。 それは意味のあるこずですが、私はガむドラむンの独断的な粟神を振り払うこずはできたせん。 私のプロゞェクトの開発者は、セレクタヌを賢く、適切な堎合に䜿甚するこずを信頌したす。これたでの私の経隓では、セレクタヌを䜿甚しおいるからです。

特定の条件䞋では、安党性ず慣習の面で間違いを犯したいず思う理由がわかりたした。 あなたの時間ず関䞎に感謝したす、私は私たちがreduxを持っおいるこずを党䜓的に非垞に嬉しく思いたす。

もちろん。 FWIWには、他のセレクタヌラむブラリがあり、Reselectのラッパヌもありたす。 たずえば、 https//github.com/planttheidea/selectoratorを䜿甚するず、ドット衚蚘のキヌパスを定矩でき、内郚で䞭間セレクタヌを実行できたす。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡