クレヌドルからのReact-reduxプロゞェクトの看護

むントロ
今幎の初めに、HeadHunterでは、クラむアント䌁業でのさたざたなHRプロセスの自動化を目的ずしたプロゞェクトを開始したした。 前面のこのプロゞェクトのアヌキテクチャは、React-Reduxスタックでした。

9か月間、圌は埓業員をテストするための小さなアプリケヌションから、今日では「才胜評䟡」ず呌ばれるマルチモゞュヌルプロゞェクトに成長したした。 成長するに぀れお、次の質問に盎面したした。


これは、コンポヌネント、レデュヌサヌのアヌキテクチャぞのアプロヌチの倉曎に珟れたした。

プロゞェクトをどのように開発し、どのような決定を䞋したかに぀いお話したしょう。 それらのいく぀かは、「holivny」であるこずが刀明するかもしれたせんが、他の人は、反察に、reduxで倧芏暡なプロゞェクトを構築する際の「クラシック」です。 以䞋に説明するプラクティスが、react-reduxアプリケヌションを構築する際に圹立぀こずを望み、実際の䟋が、このアプロヌチたたはそのアプロヌチの仕組みを理解するのに圹立぀こずを願っおいたす。

䞀般的な情報。 むントロ。


WebアプリケヌションはSPAです。 クラむアントでのみアプリケヌションをレンダリングする以䞋で理由を説明したす。 開発では、React-reduxスタックをさたざたなミドルりェア、たずえばredux-thunkずずもに䜿甚したした。 このプロゞェクトでは、アセンブリ䞭にbabelでコンパむルされたes6を䜿甚したす。 開発は、es7を䜿甚せずに実行されたす。これは、暙準では受け入れられない゜リュヌションを採甚したくないためです。
プロゞェクトはtest.hh.ruで郚分的に利甚可胜ですが、hhに登録された䌚瀟でのみ䜿甚できたす。

プロゞェクト構造


プロゞェクトの構造ずしお、最初にアプリケヌションをいく぀かの郚分に分けたした。 結果は、このスタックの「叀兞的な」構造になりたした。


ここに


この構造により、プロゞェクトの開発を開始したした。 システムのすべおの芁件ず、開発プロセス䞭に発生する可胜性のあるすべおの困難を事前に予枬するこずは䞍可胜です。 したがっお、プロゞェクトの挞進的な近代化の道を遞択したした。 次のように機胜したす。

  1. 特定のアプリケヌションモデルを遞択したす。
  2. 䞀郚のアプロヌチでは問題を垌望どおりに解決できないずいう事実に盎面しおいたす。
  3. リファクタリングを実行し、アプリケヌションの構造を倉曎したす。

時間の経過に䌎うアプリケヌションの構造の倉化を分析しおみたしょう。

構造の構築。 幌少期

プロゞェクトが若く、倚数のファむルで倧きくなりすぎおいない堎合は、単玔な構築モデルを遞択するこずをお勧めしたす。 それはたさに私たちがやったこずです。

すべおのアクションクリ゚ヌタヌは、原則に埓っお栌玍されおいたした。぀たり、1぀のグルヌプの操䜜、぀たり1぀のファむルにたずめられおいたす。 すべおのファむルは、フォルダヌ内の1぀のリストに保存されおいたした。

このように芋えた


「1぀の操䜜グルヌプ」ずは䜕ですか 1぀のアクション䜜成者ファむルが、1぀のレデュヌサヌ内のアクションを担圓しおいるず蚀えたす。 この堎合、アクションの䜜成者ずリデュヌサヌの名前は同じですが、100のケヌスでは発生したせん。 意味では、これらは1぀のタむプのオブゞェクトに察する操䜜です。 たずえば、employee.jsには、特定のオブゞェクト「埓業員」を操䜜するためのさたざたなメ゜ッドが含たれおいたす。 これは圌に関する情報の取埗、デヌタの読み蟌み゚ラヌの凊理、デヌタの倉曎、新しい埓業員の远加です。

そのような操䜜の兞型的なコヌド

 export function loadEmployee(id) { return dispatch => { //  action,   ,      employee dispatch(fetchEmployee()); fetch(`/employees/${id}`) //    .then(checkStatus) //  .then(result => result.json()) .then(result => { //  ,      (,       ,     ) dispatch(receiveEmployee(result)); }) .catch(() => { //  ,     : 1)   ; 2)    ; 3)     ; 4)    react . dispatch(releaseEmployee()); dispatch(errorRecord(t('employee.error'))); }); }; } 

このコヌドでは、サヌバヌ偎ずレデュヌサヌの動䜜ずコンポヌネントの反応の䞡方で、䞀床のキャッチで゚ラヌのグルヌプを䞀床に凊理するこずに泚意するこずが重芁です。 より詳现には、このようなアヌキテクチャを䜜成するこずにした理由は、蚘事の最埌にあるあいたいな゜リュヌションのセクションにありたす。

同様のビルドモデルがレデュヌサヌ、コンテナヌ、およびコンポヌネントに採甚されたした。 コンポヌネントの「慣習」はごくわずかです。 各コンポヌネントは個別のフォルダヌにありたす。 これにより、.jsモゞュヌルずスタむルの䞡方を配眮できたす。たた、堎合によっおは、フォルダヌ内に画像ずその他のデヌタを配眮するこずもできたす。


思春期

この構造は、最初のモゞュヌルの䜜業が終了するたで正確に存続したした。 新しいモゞュヌルに移る前に、結果のコンポヌネントのセットを冷静に芋お、システムの増加に䌎い、プロゞェクト構造に察するこのアプロヌチは混乱を招き、1぀のシステムレベルに膚倧な数のファむルが存圚するこずになりたす。 さらに、すべおのjsを1぀のファむルではなく前面に送信するこずにした堎合たずえば、jsバンドルのサむズがメガバむト単䜍のminifaen-agliphene情報で増加する堎合、しかしいく぀かのバンドルで、すべおのモゞュヌルの䟝存関係をかなり長い間解決する必芁がありたす。

そのため、次の決定を䞋したした2぀のモゞュヌルAずBに぀いお説明したすが、任意の数にスケヌリングできたす。

  1. すべおのアクションクリ゚ヌタヌ、レデュヌサヌ、およびコンテナヌは、3぀のタむプcommon、moduleA、moduleBに分類されたす。

  2. アクションタむプを蚘述しない定数はすべお、constantsフォルダヌ内にありたす。 同じフォルダヌには、必芁なアクションの皮類を説明するアクションディレクトリが含たれおいたす。 さらに、それらは2぀のタむプに分けられたす。

  3. コンポヌネントは4぀のタむプに分けられたす。

    common-䞀般的な反応モゞュヌルが含たれたす。 それらはダミヌの反応コンポヌネントを衚したす぀たり、UIを蚘述するコンポヌネントのみがそれを制埡せず、アプリケヌションの状態に盎接䟝存せず、アクションを呌び出したせん、実際には、これらはアプリケヌションのどこでも䜿甚されるコンポヌネントです。

    ブロック-アプリケヌションの党䜓的な状態に䟝存するコンポヌネント。 たずえば、ブロック「通知」たたは「通知」。
    moduleA、moduleB-モゞュヌルの特定のコンポヌネント。

    ブロックずモゞュヌルはどちらもスマヌトコンポヌネントである可胜性があり、䜕らかのアクションを匕き起こすなど

受け入れられた芏則により、アプリケヌション構造は次のようになり始めたした。


したがっお、プロゞェクトのモゞュヌルの本質を説明する明確な構造を埗たした。そこでは、jsファむルず1぀たたは別のモゞュヌルの比率を簡単に決定できたす。぀たり、モゞュヌルに異なるバンドルを䜜成するこずを決定した堎合、これは難しくありたせんちょうど「必芁な郚分ぞのWebpack」。

アプリケヌション状態のモゞュヌルぞの分離


さお、私たちはファむルを構造的に分割したしたが、目は喜ぶでしょうが、ロゞック、レデュヌサヌのレベルでのマルチモゞュヌル構造のサポヌトに぀いおはどうでしょうか

小芏暡なアプリケヌションの堎合、ルヌトレデュヌサヌの説明は通垞次のずおりです。

 export const createReducer = () => { return combineReducers({ account, location, records, managers, tooltip, validation, progress, restrictedData, command, translations, status, features, module, settings, menu, routing: routeReducer, }); }; 

小芏暡なアプリケヌションの堎合、すべおのデヌタが単玔なコレクションにあるため、これは䟿利です。 しかし、アプリケヌションのサむズが増加するず、転送されるデヌタの数が増加するため、レデュヌサヌを粉砕しおモゞュヌルに分割する必芁がありたす。 これをどのように行うこずができたすか 結果に移る前に、2぀の状況を怜蚎したす。

最初の状況「オブゞェクトを個々の枛速機に粉砕する」

埓業員゚ンティティがあるずしたす。 この゚ンティティは、さたざたな状況を分析し、意思決定を蚘述するのに最適です。 ゚ンティティ「埓業員」を䜿甚しお、䌚瀟のマネヌゞャヌはさたざたなアクションを実行できたす。アップロヌド、線集、䜜成、テストぞの招埅、テスト結果の衚瀺。 このフィヌルドは、ステヌタスずデヌタの2぀のフィヌルドを持぀オブゞェクトです。 statusは、フィヌルドの珟圚の状態FETCH \ COMPLETE \ FAIL、およびデヌタ-有甚なデヌタ、埓業員の配列を決定したす。 これは、サヌバヌからデヌタを取埗し、埓業員のリストを衚瀺するのに十分です。
次に、埓業員を遞択する機胜を远加する必芁がありたす。


この問題を解決するには、次の3぀の方法がありたす。

方法1

employees.data配列内の芁玠を倉曎しお、id、name、surname、positionに加えお、各芁玠に遞択したフィヌルドが含たれるようにしたす。 チェックボックスをレンダリングするずき、このフィヌルドを芋お、たずえば次のように合蚈金額を考慮したす。

 employees.data.reduce((employee, memo) => employee.selected ? memo + 1 : memo, 0); 

将来、遞択したIDを送信する必芁がある堎合、それらはすべお同じフィルタヌを介しお怜出されたす。 遞択したものの远加/削陀は、マップを介しお同様に行われたす。 この方法の利点は、デヌタが䞀元的に保存されるこずです。 欠点は、「くしゃみ」ごずにオブゞェクト党䜓に觊れるこずです遞択したフラグを远加/削陀したす。 これにより、かなりの数のアクションが発生したす。 遞択した埓業員ず連携するためのロゞックが、埓業員削枛者、アクション䜜成者に远加されたす。 これらの郚分を分離したい堎合遞択した埓業員ず連携しおも埓業員削枛者のメむンタスクに圱響しないため、埓業員を削陀しおペヌゞネヌションを行う、他の2぀の方法を怜蚎する必芁がありたす。

2番目の方法

selectedEmployeesなどの別のレデュヌサヌを䜜成したす。 これは䞍倉のマップであり必芁に応じお、オブゞェクトのみを配列できたす、遞択したIDのみを栌玍したす。 この構造にidを远加および削陀するず、はるかに簡単に芋えたす。 チェックボックスのレンダリングは、パスstore.selectedEmployees.has(id)に埓う必芁があるずいう事実によっおのみ耇雑になりたす。 したがっお、遞択した埓業員ずのすべおの䜜業は、別個のレデュヌサヌ、別個のアクショングルヌプに送られたす。

この゜リュヌションは、状態の他の郚分を倉曎およびロヌドせず、近くに別の郚分を远加するずいう点で優れおいたす。 したがっお、アプリケヌションがこれら2぀のレデュヌサヌで構成されおいる堎合、次の構造が埗られたす。

 employees {state: COMPLETE, data: [{id: 1, ...}, {id: 2, ...}]} selectedEmployees Map({1 => true}) 

3番目の方法

時間が経぀に぀れお、毎回2番目のメ゜ッドを䜿甚するず、埓業員、selectedEmployees、埓業員、employeeTestなどで構成される肥倧化した状態になりたす。リデュヌサヌは盞互に関連しおいるこずに泚意しおくださいselectedEmployeesは埓業員を指し、employeeTestは埓業員を指したす。 したがっお、耇合枛速機を䜜成しおアプリケヌションを構成したす。 これにより、より明確で䟿利な構造が埗られたす。

 employees: - list [{id: 1, ...}, {id: 2, ...}] - selected Map({1 => true}) - status COMPLETE employee: - data - test 

このような構造は、レデュヌサヌの階局を構築するこずで実珟できたす。

 export const createReducer = () => { return combineReducers({ employees: combineReducers({ list: employees, selected: selectedEmployees, status: employeesStatus }) routing: routeReducer, }); }; 

泚このレベルではステヌタスは重芁ではありたせん。以前のように、埓業員のリストを担圓するリデュヌサヌ内に残すこずができたす。

これが、䜿甚するこずにした方法です。 オブゞェクトのグルヌプ䜜業が必芁なさたざたな状況に最適です。

状況2「デヌタの正芏化」

SPAの開発では、デヌタの正芏化が倧きな圹割を果たしたす。 今埌も埓業員ず協力しおいきたす。 適切な埓業員を遞択し、テストに送りたした。 その埌、埓業員は合栌し、䌚瀟はテスト結果を受け取りたす。 アプリケヌションにはデヌタを保存する必芁がありたす-埓業員のテスト結果。 1人の埓業員が耇数の結果を持぀堎合がありたす。
同様の問題は、いく぀かの方法でも解決できたす。

悪い道男バンド

この方法は、テストに関する完党なデヌタを内郚に保存するような方法で埓業員構造を改良するこずを提案したす。 それは

 employees: { status: COMPLETE, list: [ { id: 1, name: '', testResults: { id: 123, score: 5 speed: 146, description: '...' ... } } ] } 

ストアにオヌケストラオブゞェクトを取埗したした。 これは䞍䟿で、䜙分なネストがありたす。 正芏化されたデヌタを䜿甚した゜リュヌションは、ずっずきれいに芋えたす。

いい方法

埓業員ずテストにはidがあるこずに泚意しおください。 デヌタベヌスには、埓業員IDだけでテストず埓業員の間に接続がありたす。 バック゚ンドから同じアプロヌチを取り、次の構造を取埗したす。

 employees: { status: COMPLETE, list: [ { id: 1, name: '', testResults: [123] } ] }, tests: { 123: { id: 123, score: 5 speed: 146, description: '...' ... } } 

ルヌトレデュヌサヌでは次のようになりたす。

 export const createReducer = () => { return combineReducers({ employees: combineReducers({ list: employees, selected: selectedEmployees, status: employeesStatus }), tests, routing: routeReducer, }); }; 

ストアを構築し、すべおを棚に眮き、アプリケヌションの機胜を明確に理解したした。

モゞュヌルを远加する

モゞュヌルを远加するずき、状態ビュヌを共通のグルヌプず異なるモゞュヌルに属するグルヌプに分割したす。

 export const createReducer = () => { return combineReducers({ moduleA: combineReducers({ employees: combineReducers({ list: employees, selected: selectedEmployees, status: employeesStatus }), tests, }), moduleB: combineReducers({...}), // common     ,    notifications, routing: routeReducer, }); }; 

このメ゜ッドを䜿甚するず、ストアの構造内でファむル構造を繰り返すこずができたす。 したがっお、アプリケヌションの構造は、ファむルレベルず論理レベルの䞡方で繰り返されたす。 これは、アプリケヌション党䜓の䜜業党䜓の理解が簡玠化され、新しい開発者がプロ​​ゞェクトに参加するためのしきい倀が䜎くなるこずを意味したす。

React Component Buildingの原則


アプリケヌション構造の構築に成功し、コヌドをモゞュヌルに分割したした。アクションずレデュヌサヌは階局的であり、スケヌラブルなコヌドを蚘述できたす。 UIを担圓するコンポヌネントをどのように構築するかずいう質問に戻りたしょう。

私たちはリデュヌスの原則を順守したす。぀たり、グロヌバルな偎面が唯䞀の真実の源です。 私たちの目暙は、ストアからのデヌタに応じお、い぀でもサむトの衚瀺を完党に埩元できるようにアプリケヌションを構築するこずです。 蚱容される゚ラヌのうち、アニメヌション/ドロップダりンの状態、ツヌルチップ-オヌプン/クロヌズに関するデヌタを埩元しないようにしたす。

これらの条件に基づいお、アプリケヌションモデルを構築したす。

スマヌトコンポヌネントずダムコンポヌネント

以䞋のリ゜ヌスでこれらの特性を構築および分離するための十分に説明されたアプロヌチ

» Medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.aszvx1fh1
» Jaketrent.com/post/smart-dumb-components-react

同様のアプロヌチを取りたす。 すべおの共通コンポヌネントは、プロパティなどのみを受け取るダミヌコンポヌネントです。特定のモゞュヌルに関連するコンポヌネントは、スマヌトたたはダムのいずれかです。 構造内でそれらを明確に区別するのではなく、近くに保存されたす。

きれいな郚品

ほがすべおのコンポヌネントに独自の状態はありたせん。 そのようなコンポヌネントは、接続デコレヌタを介しお、たたは䞊䜍コンポヌネントからの「りォヌタヌフォヌル」の助けを借りお、状態、アクション䜜成者を受け取りたす。

しかし、独自の状態を持぀コンポヌネントの玄5がありたす。 これらのコンポヌネントは䜕ですか 圌らのアヌトには䜕が保存されおいたすか このアプリケヌションの同様のコンポヌネントは、2぀のグルヌプに分けるこずができたす。

ポップアップステヌタス


別の䟋


このグルヌプには、情報を保存するコンポヌネントが含たれたす-ポップアップ芁玠ドロップダりン、ツヌルチップを衚瀺するかどうか。

そのようなコンポヌネントの兞型的なコヌド

 import React, { Component } from 'react'; import PseudoLink from '../pseudoLink/pseudoLink'; import Dropdown from '../../common/dropdown/dropdown'; import './dropdownHint-styles.less'; class DropdownHint extends Component { constructor(props, context) { super(props, context); this.state = { dropdown: false, }; } renderDropdown() { if (!this.state.dropdown) { return ''; } return ( <Dropdown onClose={() => { this.setState({ dropdown: false, }); }}> <div className='dropdown-hint'>{this.props.children}</div> </Dropdown> ); } render() { return ( <PseudoLink onClick={() => { this.setState({ dropdown: true, }); }}> {this.renderDropdown()} {this.props.text} </PseudoLink> ); } } export default DropdownHint; 


内郚状態の2番目のタスク䞀時的なキャッシュたたは远加。


次の䟋を考えおみたしょう。


画面䞊郚の通知は、衚瀺たたは非衚瀺になるずアニメヌション化されたす。 通知の本質はグロヌバルアプリケヌション状態に保存されたすが、通知を非衚瀺にするその埌の削陀を䌎うプロセスでは、アニメヌションなどの重芁でない情報でグロヌバル状態を汚染するこずなく、いく぀かのアプロヌチのいずれかを䜿甚できたす。

最初の方法はキャッシュです。
かなり簡単な方法。 NotificationsManagerコンポヌネントを䜜成したす。これは、Notificationコンポヌネントのレンダリングを担圓したす。 NotificationsManagerが次の通知をレンダリングした埌、タむマヌを開始し、その埌、通知を非衚瀺にするアクションが呌び出されたす。 呌び出す前に、NotificationsManagerは通知をキャッシュしたす。 これにより、通知自䜓をストアから削陀できたす。たた、コンポヌネントのロヌカル状態内のキャッシュされたデヌタにより、消倱をアニメヌション化できたす。
この方法は、私たちの偎を欺くずいう点で䞍䟿です-圌は通知がないず信じおいたすが、実際にはコンポヌネントのロヌカルバヌゞョンに保存されおいたす。 「誠実な」パヌティが必芁なので、この方法は私たちには適しおいたせん。

2番目の方法-ストアからの情報をロヌカルに補完したす。
この方法は、ストアからデヌタを埩元するための高粟床を劚げないため、より正盎で魅力的です。 NotificationsManagerは、ストアの偎から通知ぞの倉曎を受け取るず、通知で実行する必芁のある情報倖芳の衚瀺、消倱、たたは䜕もしないに関する情報をその状態に远加するずいう事実から成りたす。 この堎合、NotificationManagerは、通知の消倱のアニメヌションが完了した堎合にのみ、CLOSE_NOTIFICATIONアクションを介しおパヌティに通知したす。 このアプロヌチにより、ストア内の䞍必芁な情報通知アニメヌションステヌタスを砎棄するこずができ、同時にストアは「唯䞀の真実の源」であり、アプリケヌション党䜓の衚瀺を正確に埩元できたす。

このアプロヌチがどのように機胜するかをおおよそ説明したす。 ストアでは次のものを取埗したす。

 notifications: [ { id: 1, text: '  ,   ' }, { id: 2, text: '  ,   ' }, { id: 3, text: '  , ?' }, ] 

ロヌカルコンポヌネントのスタむル

 notifications: { 1: 'out', 3: 'in' } 

䟋を芋おみたしょう。 アプリケヌション党䜓のレベルでは、3぀の通知があるこずがわかりたす。 コンポヌネントのロヌカルレベルでは、アプリケヌションにずっお意味を持たない情報を保存したすが、ロヌカルレンダリングには重芁です。id=== 1が消え、id == 3が残り、id === 2は静的です。

, . , . . “- ”.

. , , , . . , . .

.


. react-router, redux react-router-redux.
.
, json, : , , ( ). .

:

  1. js ;
  2. , ;
  3. node.js .

json-. acceptType-.

:


employees (employees) (account).

, html-, json:

 window.pageData = { account: //    employees: //    } 

, , .

:

 const initialData = window.pageData.employees; export default function employees(state = initialData, actions) { // reducer } 

employees , -, .

— . action creator, acceptType: application/json ( ). . “ ”.



action creator':

 export function loadEmployee(id) { return dispatch => { //  action,   ,      employee dispatch(fetchEmployee()); fetch(`/employees/${id}`) //    .then(checkStatus) //  .then(result => result.json()) .then(result => { //  ,      (,       ,     ) dispatch(receiveEmployee(result)); }) .catch(() => { dispatch(releaseEmployee()); dispatch(errorRecord(t('employee.error'))); }); }; } 

receiveEmployee. , , , . . — catch :

  1. ;
  2. ;
  3. ;
  4. react .

- “” . , , t('employee.error'). t — , ().

“” . , , , . . , : . . , :

 export function loadEmployee(id) { return async dispatch => { //  action,   ,      employee dispatch(fetchEmployee()); let json; try { const res = await fetch(`/employees/${id}`); checkStatus(res); json = await getJson(res); } catch () { dispatch(releaseEmployee()); dispatch(errorRecord(t('employee.error'))); } dispatch(receiveEmployee(result)); }; } 

try-catch dispatch:

dispatch(receiveEmployee(result));

, catch:

 export function loadEmployee(id) { return async dispatch => { //  action,   ,      employee dispatch(fetchEmployee()); let json; try { const res = await fetch(`/employees/${id}`); checkStatus(res); json = await getJson(res); } catch () { dispatch(releaseEmployee()); dispatch(errorRecord(t('employee.error'))); } try { dispatch(receiveEmployee(result)); } catch() { dispatch(releaseEmployee()); dispatch(errorRecord(t('employee.error'))); } }; } 

, .

, , , , .


, , , “ ”. (, 5—10 , 40—50 ) . ? , . , . , “ ” , . , , , -, , -, (, , ). , , . . , .

:
» github.com/reactjs/redux/issues/37#issue-85098222
» gist.github.com/gaearon/0a2213881b5d53973514
» stackoverflow.com/questions/34095804/replacereducer-causing-unexpected-key-error

:

ステップ1
, . , . ( ).

ステップ2
. :

 export const createReducer = () => { return combineReducers({ moduleA: combineReducers({ employee: combineReducers({ list: employees, selected: selectedEmployees, status: employeesStatus }), tests, }), moduleB: combineReducers({...}), // common     ,    notifications, routing: routeReducer, }); } 

:

 export const createReducer = (dynamicReducers = {}) => { return combineReducers(Object.assign({}, { notifications, routing: routeReducer, // ,    module, }, dynamicReducers)); }; 

, :

 export const aReducers = { moduleA: combineReducers({ employee: combineReducers({ list: employees, selected: selectedEmployees, status: employeesStatus }), tests, }), } 

ステップ3
, :

 export function configureStore() { const store = createStoreWithMiddleware(createReducer()); store.dynamicReducers = {}; storeInstance = store; switch (store.getState().module) { case A: injectAsyncReducer(aReducers); break case B: injectAsyncReducer(bReducers); break; //   } return store; } export function injectAsyncReducer(reducers) { if (reducers !== storeInstance.dynamicReducers) { storeInstance.dynamicReducers = reducers; storeInstance.replaceReducer(createReducer(storeInstance.dynamicReducers)); } } 

injectAsyncReducer, .

ステップ4
action creator. action . :

 export const checkoutAModule = () => { //    injectAsyncReducer(aReducers); return { type: CHECKOUT_MODULE, module: A, }; }; 

, , .

ステップ5
, . :

 import React, { Component } from 'react'; import { connect } from 'react-redux'; import { checkoutModuleA } from '../../actions/module'; import { A } from '../../constants/module'; export default function checkoutA() { return Container => { class AContainer extends Component { componentWillMount() { if (this.props.module !== A) { this.props.checkoutModuleA(); } } render() { return ( <Container {...this.props} /> ); } } return connect( state => { return { module: state.module, }; }, { checkoutModuleA, } )(AContainer); }; } 

, , .

6.
:

 import React, { Component } from 'react'; import { connect } from 'react-redux'; import { compose } from 'redux'; import Content from '../components/content/content'; import Managers from '../components/managers/managers'; import composeRestricted from './restricted/restricted'; import { loadManagers } from '../actions/managers'; import title from './title/title'; class ManagersPage extends Component { componentWillMount() { if (!this.props.firstLoad) { this.props.loadManagers(this.props.location); } } render() { return ( <div className='page'> <Content> <Managers /> </Content> </div> ); } } export default compose( connect( state => state.location, {loadManagers} ), checkoutA(), title('managers', 'title.base'), composeRestricted({user: true}) )(ManagersPage); 

できた . , . , “” . (, , ).


. , . , , , , . , ( ), .

Source: https://habr.com/ru/post/J310524/


All Articles