MrrReactの合蚈FRP

Mrrは、Reactの機胜的に反応するラむブラリです架空のトヌトロゞヌに぀いおは謝眪したす。



「反応性」ずいう蚀葉は通垞、参照FRPずしおRx.jsを指したす。 ただし、このテヌマに関するHabréの䞀連の最近の蚘事 [1] 、 [2] 、 [3] は、Rxの゜リュヌションの扱いにくいこずを瀺したした。 Rxは倧きく匷力であり、フロヌの抜象化自䜓が瀺唆する問題の解決に最適です実際には、これは䞻に非同期タスクの調敎です。 しかし、たずえば、Rxで単玔な同期フォヌム怜蚌を䜜成したすか 圌は通垞の呜什型アプロヌチず比范しおあなたの時間を節玄したすか



mrrは、FRFが特定の「ストリヌミング」問題だけでなく、最も䞀般的な日垞のフロント゚ンドタスクでも䟿利で効果的な゜リュヌションになり埗るこずを蚌明する詊みです。



リアクティブプログラミングは非垞に匷力な抜象化であり、珟時点ではフロント゚ンドに2぀の方法で存圚したす。





Mrrはこれらのアプロヌチの利点を組み合わせおいたす。 Rx.jsずは異なり、mrrにはナヌザヌが远加しお拡匵できる短いAPIがありたす。 倚数のメ゜ッドず挔算子の代わりに-Observableホットずコヌルド、Subjectなどの代わりに4぀の基本挔算子 -1぀の抜象化ストリヌム。 たた、mrrには、コヌドの読みやすさを倧幅に耇雑にする可胜性のある耇雑な抂念メタストリヌムなどがありたせん。



ただし、mrrは「新しい方法で簡玠化されたRx」ではありたせん。 Rxず同じ基本原則に基づいお、mrrはアプリケヌションのグロヌバルおよびロヌカルコンポヌネントレベル状態を管理する、より倧きなニッチであるず䞻匵しおいたす。 リアクティブプログラミングの元の抂念は非同期タスクで動䜜するこずを目的ずしおいたしたが、mrrは通垞の同期タスクにリアクティブアプロヌチをうたく䜿甚しおいたす。 これが「総FRP」の原則です。



倚くの堎合、Reactでアプリケヌションを䜜成する際に、耇数の異皮テクノロゞヌが䜿甚されたすコンポヌネント状態の再構成たたはすぐに-フック、グロヌバル状態のRedux / mobx、副䜜甚を管理し非同期を調敎するためのredux-observableたたはthunk / sagaを持぀Rx゚ディタヌのタスク。 同じアプリケヌション内のさたざたなアプロヌチやテクノロゞヌの「サラダ」の代わりに、mrrを䜿甚するず、単䞀のテクノロゞヌずパラダむムを䜿甚できたす。



mrrむンタヌフェヌスは、Rxや同様のラむブラリヌずも倧きく異なりたす-より宣蚀的です。 反応性の抜象化ず宣蚀的アプロヌチのおかげで、mrrは衚珟力豊かで簡朔なコヌドを曞くこずができたす。 たずえば、 mrr䞊の暙準のTodoMVCは、50行未満のコヌドJSXテンプレヌトをカりントしたせんで枈みたす。



しかし、十分な広告。 「軜い」RPず「重い」RPの利点を1぀のボトルにたずめるこずができたしたか。刀断する必芁がありたすが、最初にコヌド䟋を読んでください。



TodoMVCはすでにかなり痛いので、Githubナヌザヌに関するデヌタをダりンロヌドする䟋はあたりにも原始的で、ラむブラリの機胜を感じるこずができたせん。 鉄道チケットを賌入するための条件付きアプリケヌションの䟋ずしお、mrrを怜蚎したす。 UIには、開始ステヌションず終了ステヌション、日付を遞択するためのフィヌルドがありたす。 次に、デヌタを送信した埌、利甚可胜な列車ずその䞭の堎所のリストが返されたす。 特定の列車ず車の皮類を遞択するず、ナヌザヌは乗客デヌタを入力しお、チケットをバスケットに远加したす。 行こう



ステヌションず日付を遞択できるフォヌムが必芁です。







ステヌションを入力するためのオヌトコンプリヌトフィヌルドを䜜成したす。



import { withMrr } from 'mrr'; const stations = [ '', '', '', ' ', ... ] const Tickets = withMrr({ //    $init: { stationFromOptions: [], stationFromInput: '', }, //   - "" stationFromOptions: [str => stations.filter(s => s.indexOf(str)===0), 'stationFromInput'], }, (state, props, $) => { return (<div> <h3>    </h3> <div>  : <input onChange={ $('stationFromInput') } /> </div> <ul className="stationFromOptions"> { state.stationFromOptions.map(s => <li>{ s }</li>) } </ul> </div>); }); export default Tickets;
      
      





mrrコンポヌネントはwithMrr関数を䜿甚しお䜜成されたす。この関数は、リアクティブリンク図フロヌの説明ずレンダリング関数を受け入れたす。 レンダリング関数は、状態だけでなくコンポヌネントの小道具にも枡されたすが、珟圚はmrrによっお完党に制埡されおいたす。 これには、初期倀ブロック$ initが含たれ、反応セルの数匏倀によっお蚈算されたす。



これで、2぀のセルたたは同じものである2぀のストリヌムがありたす stationFromInput 、 $ヘルパヌを䜿甚したナヌザヌ入力からの倀デヌタ入力芁玠に察しおevent.target.valueをデフォルトで枡す、およびそれから掟生したセル名前で䞀臎するステヌションの配列を含むstationFromOptions 。



stationFromOptionsの倀は、関数を䜿甚しお芪セルが倉曎されるたびに自動的に蚈算されたすExcelの数匏に䌌た「 数匏 」ず呌ばれるmrr甚語で。 mrr匏の構文は単玔です。最初は、セルの倀を蚈算する関数たたは挔算子です。次に、このセルが䟝存するセルのリストがありたす。倀は関数に転送されたす。 このような奇劙な䞀芋した構文には倚くの利点がありたすが、これに぀いおは埌で怜蚎したす。 これたでのずころ、ここでのmrrロゞックは、Vue、Svelte、およびその他のラむブラリで䜿甚される蚈算可胜な倉数を䜿甚した通垞のアプロヌチに䌌おいたすが、唯䞀の違いは玔粋な関数を䜿甚できるこずです。



入力フィヌルドのリストから遞択したステヌションの眮換を実装したす。 ナヌザヌがいずれかのステヌションをクリックした埌に、ステヌションのリストを非衚瀺にするこずも必芁です。



 const Tickets = withMrr({ $init: { stationFromOptions: [], stationFromInput: '', }, stationFromOptions: [str => stations.filter(s => str.indexOf(a) === 0), 'stationFromInput'], stationFrom: ['merge', 'stationFromInput', 'selectStationFrom'], optionsShown: ['toggle', 'stationFromInput', 'selectStationFrom'], }, (state, props, $) => { return (<div> <div>  : <input onChange={ $('stationFromInput') } value={ state.stationFrom }/> </div> { state.optionsShown && <ul className="stationFromOptions"> { state.stationFromOptions.map(s => <li onClick={ $('selectStationFrom', s) }>{ s }</li>) } </ul> } </div>); });
      
      





ステヌションのリストで$ヘルパヌを䜿甚しお䜜成されたむベントハンドラヌは、各オプションの固定倀を出力したす。



mrrは、その宣蚀的アプロヌチに䞀貫性があり、あらゆる突然倉異ずは無関係です。 ステヌションを遞択した埌、セル倀を「匷制」倉曎するこずはできたせん。 代わりに、新しいstationFromセルを䜜成したす。 このセルは、マヌゞストリヌム挔算子Rxの近䌌倀はcomposeLatestを䜿甚しお、ナヌザヌ入力 stationFromInput ずステヌション遞択 selectStationFrom の2぀のストリヌムの倀を収集したす。



ナヌザヌが䜕かを入力した埌にオプションのリストを衚瀺し、オプションの1぀を遞択した埌に非衚瀺にしたす。 optionsShownセルは、他のセルの倉曎に応じおブヌル倀を取るオプションのリストの可芖性を担圓したす。 これは、構文糖が存圚する非垞に䞀般的なパタヌン、 トグル挔算子です。 最初の匕数ストリヌムが倉曎されるずセルの倀がtrueに蚭定され、2番目の匕数がfalseに蚭定されたす 。



入力したテキストをクリアするボタンを远加したす。



 const Tickets = withMrr({ $init: { stationFromOptions: [], stationFromInput: '', }, stationFromOptions: [str => stations.filter(s => str.indexOf(a) === 0), 'stationFromInput'], clearVal: [a => '', 'clear'], stationFrom: ['merge', 'stationFromInput', 'selectStationFrom', 'clearVal'], optionsShown: ['toggle', 'stationFromInput', 'selectStationFrom'], }, (state, props, $) => { return (<div> <div>  : <input onChange={ $('stationFromInput') } value={ state.stationFrom }/> { state.stationFrom && <button onClick={ $('clear') }></button> } </div> { state.optionsShown && <ul className="stationFromOptions"> { state.stationFromOptions.map(s => <li onClick={ $('selectStationFrom', s) }>{ s }</li>) } </ul> } </div>); });
      
      





入力フィヌルドのテキストの内容を担圓するstationFromセルは、2぀のストリヌムからではなく、3぀のストリヌムから倀を収集したす。 このコヌドは単玔化できたす。 [* formula *、* ... cell arguments *]ずいう圢匏のmrrコンストラクトは、LispのS匏に䌌おおり、Lispのように、このような構造を任意に盞互にネストできたす。



無駄なclearValセルを取り陀き、コヌドを短くしたしょう。



  stationFrom: ['merge', 'stationFromInput', 'selectStationFrom', [a => '', 'clear']],
      
      





呜什型スタむルで曞かれたプログラムは、組織化されおいないチヌムず比范するこずができたす。チヌムは垞にお互いに䜕かを泚文したすメ゜ッド呌び出しず倉曎の倉曎をお勧めしたす。さらに、䞡方のマネヌゞャヌは郚䞋であり、その逆も同様です。 宣蚀的なプログラムは、反察のナヌトピア的な図に䌌おいたす。぀たり、誰もがどのような状況でもどのように行動すべきかを明確に知っおいる集団です。 そのようなチヌムでは泚文の必芁はありたせん;誰もがちょうど圌らの堎所にいお、起こっおいるこずに反応しお働いおいたす。



むベントの考えられるすべおの結果を説明する代わりに特定の突然倉異を起こすために読む、このむベントが発生する可胜性のあるすべおのケヌスを説明したす。 セルが他のセルの倉曎にどのような倀を取るか。 これたでの小さな䟋では、stationFromセルずその倀に圱響する3぀の状況に぀いお説明したした。 呜什型コヌドに慣れおいるプログラマヌにずっお、このアプロヌチは珍しいように思えるかもしれたせんたたは「束葉杖」、「倒錯」さえ。 実際、実際に芋られるように、コヌドの簡朔さおよび安定性のために劎力を節玄できたす。



非同期性はどうですか ajaxで提案されたステヌションのリストをプルアップするこずは可胜ですか 問題ありたせん 本質的に、関数が倀を返すかプロミスを返すかは、mrrにずっお重芁ではありたせん。 mrr promiseが返されるず、その解決を埅っお、受信したデヌタをストリヌムに「プッシュ」したす。



 stationFromOptions: [str => fetch('/get_stations?str=' + str).then(res => res.toJSON()), 'stationFromInput'],
      
      





たた、非同期関数を数匏ずしお䜿甚できるこずも意味したす。 より耇雑なケヌス゚ラヌ凊理、玄束のステヌタスは埌で怜蚎されたす。



出発駅を遞択する機胜が甚意されたした。 到着ステヌションに同じものを耇補するこずは意味がありたせん。再利甚できる別のコンポヌネントに入れる䟡倀がありたす。 これは自動補完機胜を備えた䞀般化された入力コンポヌネントになるため、フィヌルドの名前を倉曎し、propsで適切なオプションセットを取埗するための関数を䜜成したす。



 const OptionsInput = withMrr(props => ({ $init: { options: [], }, val: ['merge', 'valInput', 'selectOption', [a => '', 'clear']], options: [props.getOptions, 'val'], optionsShown: ['toggle', 'valInput', 'selectOption'], }), (state, props, $) => <div> <div> <input onChange={ $('valInput') } value={ state.val } /> </div> { state.optionsShown && <ul className="options"> { state.options.map(s => <li onClick={ $('selectOption', s) }>{ s }</li>) } </ul> } { state.val && <div className="clear" onClick={ $('clear') }> X </div> } </div>)
      
      





ご芧のずおり、mrrセルの構造をpropsコンポヌネントの関数ずしお指定できたすただし、初期化時に1回だけ実行され、propsの倉曎には応答したせん。



コンポヌネント間の通信



次に、このコンポヌネントを芪コンポヌネントに接続し、mrrが関連コンポヌネントがデヌタを亀換できるようにする方法を確認したす。



 const getMatchedStations = str => fetch('/get_stations?str=' + str).then(res => res.toJSON()); const Tickets = withMrr({ stationTo: 'selectStationFrom/val', stationFrom: 'selectStationTo/val', }, (state, props, $, connectAs) => { return (<div> <OptionsInput { ...connectAs('selectStationFrom') } getOptions={ getMatchedStations } /> - <OptionsInput { ...connectAs('selectStationTo') } getOptions={ getMatchedStations } /> <input type="date" onChange={ $('date') } /> <button onClick={ $('searchTrains') }></button> </div>); });
      
      





芪コンポヌネントを子コンポヌネントに関連付けるには、 connectAs関数render関数の4番目の匕数を䜿甚しおパラメヌタヌを枡す必芁がありたす。 この堎合、子コンポヌネントに付けたい名前を瀺したす。 この方法でコンポヌネントをアタッチするこずにより、この名前でそのセルにアクセスできたす。 この堎合、val cellsを聞いおいたす。 逆も可胜です-芪セルの子コンポヌネントからリッスンしたす。



ご芧のずおり、ここでmrrは宣蚀的なアプロヌチに埓いたす。onChangeコヌルバックは䞍芁です。connectAs関数で子コンポヌネントの名前を指定するだけで、その埌セルにアクセスできたす。 この堎合も、宣蚀性のために、別のコンポヌネントの䜜業に干枉の脅嚁はありたせん。その䞭の䜕かを「倉曎」する胜力はありたせん。倉異しお、デヌタを「聞く」こずしかできたせん。



信号ず倀



次の段階では、遞択したパラメヌタヌに適した列車を怜玢したす。 呜什型のアプロヌチでは、おそらく特定のプロセッサを䜜成しおonSubmitフォヌムを送信したす。これにより、さらにアクションajaxリク゚ストず結果の衚瀺が開始されたす。 しかし、あなたが芚えおいるように、私たちは䜕も「泚文」するこずはできたせん フォヌムのセルから掟生した別のセルのセットのみを䜜成できたす。 もう1぀のリク゚ストを曞きたしょう。



 const getTrains = (from, to, date) => fetch('/get_trains?from=' + from + '&to=' + to + '&date=' + date).then(res => res.toJSON()); const Tickets = withMrr({ stationFrom: 'selectStationFrom/val', stationTo: 'selectStationTo/val', results: [getTrains, 'stationFrom', 'stationTo', 'date', 'searchTrains'], }, (state, props, $, connectAs) => { return (<div> <OptionsInput { ...connectAs('selectStationFrom') } getOptions={ getMatchedStations } /> - <OptionsInput { ...connectAs('selectStationTo') } getOptions={ getMatchedStations } /> <input type="date" onChange={ $('date') } /> <button onClick={ $('searchTrains') }></button> </div>); });
      
      





ただし、このようなコヌドは期埅どおりに機胜したせん。 匕数のいずれかが倉曎されるず、蚈算セル倀の再蚈算がトリガヌされるため、たずえば「怜玢」をクリックするだけでなく、最初のステヌションを遞択した盎埌にリク゚ストが送信されたす。 䞀方では、ステヌションず日付が匏の匕数に枡される必芁がありたすが、他方では、それらの倉曎に応答したせん。 mrrには、パッシブリスニングず呌ばれるこのための゚レガントなメカニズムがありたす。



  results: [getTrains, '-stationFrom', '-stationTo', '-date', 'searchTrains'],
      
      





セル名の前にマむナス蚘号を远加するだけです。 珟圚、 結果はsearchTrainsセルぞの倉曎にのみ応答したす。



この堎合、 searchTrainsセルは「セル信号」ずしお機胜し、 stationFromなどのセルは「セル倀」ずしお機胜したす。 シグナルセルの堎合、倀が「流れる」瞬間だけが重芁であり、どのようなデヌタになるのか-ずにかく、それは単にtrue、1たたはその他この堎合、これらはDOMむベントオブゞェクトになりたす  倀セルの堎合、その倀は重芁ですが、同時にその倉化の瞬間は重芁ではありたせん。 これらの2皮類のセルは盞互に排他的ではありたせん。倚くのセルはシグナルず倀の䞡方です。 mrrの構文レベルでは、これらの2皮類のセルはたったく異なりたせんが、リアクティブコヌドを蚘述する際には、このような違いを抂念的に理解するこずが非垞に重芁です。



ストリヌムを分割する



列車の座垭を怜玢するリク゚ストには時間がかかる堎合があるため、ロヌダヌを衚瀺し、゚ラヌが発生した堎合に察応する必芁がありたす。 自動解決によるこのデフォルトのアプロヌチには、すでにいく぀かの玄束がありたす。



 const Tickets = withMrr({ $init: { results: {}, } stationFrom: 'selectStationFrom/val', stationTo: 'selectStationTo/val', searchQuery: [(from, to, date) => ({ from, to, date }), '-stationFrom', '-stationTo', '-date', 'searchTrains'], results: ['nested', (cb, query) => { cb({ loading: true, error: null, data: null }); getTrains(query.from, query.to, query.date) .then(res => cb('data', res)) .catch(err => cb('error', err)) .finally(() => cb('loading', false)) }, 'searchQuery'], availableTrains: 'results.data', }, (state, props, $, connectAs) => { return (<div> <div> <OptionsInput { ...connectAs('selectStationFrom') } getOptions={ getMatchedStations } /> - <OptionsInput { ...connectAs('selectStationTo') } getOptions={ getMatchedStations } /> <input type="date" onChange={ $('date') } /> <button onClick={ $('searchTrains') }></button> </div> <div> { state.results.loading && <div className="loading">...</div> } { state.results.error && <div className="error"> . ,  .   .</div> } { state.availableTrains && <div className="results"> { state.availableTrains.map((train) => <div />) } </div> } </div> </div>); });
      
      





ネストされた挔算子を䜿甚するず、デヌタをサブセルに「分解」できたす。このため、匏の最初の匕数はコヌルバックであり、サブセル1぀以䞊にデヌタを「プッシュ」できたす。 これで、゚ラヌ、Promiseのステヌタス、および受信したデヌタを担圓する個別のストリヌムができたした。 ネストされた挔算子は非垞に匷力なツヌルであり、mrrには数少ない呜什の1぀ですデヌタを配眮するセルを指定したす。 マヌゞ挔算子は耇数のスレッドを1぀に結合したすが、ネストするずスレッドは耇数のサブスレッドに分割されるため、その逆になりたす。



䞊蚘の䟋は、promiseを操䜜する暙準的な方法です。mrrでは、promise挔算子ずしお䞀般化されおおり、コヌドを短瞮できたす。



  results: ['promise', (query) => getTrains(query.from, query.to, query.date), 'searchQuery'], //     availableTrains: 'results.data',
      
      





たた、promise挔算子は、最新のpromiseの結果のみが䜿甚されるようにしたす。







利甚可胜な座垭を衚瀺するためのコンポヌネント簡単にするために、さたざたな皮類の車を拒吊したす



 const TrainSeats = withMrr({ selectSeats: [(seatsNumber, { id }) => new Array(Number(seatsNumber)).fill(true).map(() => ({ trainId: id })), '-seatsNumber', '-$props', 'select'], seatsNumber: [() => 0, 'selectSeats'], }, (state, props, $) => <div className="train">  №{ props.num } { props.from } - { props.to }.   : { props.seats || 0 } { props.seats && <div>     : <input type="number" onChange={ $('seatsNumber') } value={ state.seatsNumber || 0 } max={ props.seats } /> <button onClick={ $('select') }></button> </div> } </div>);
      
      





数匏で小道具にアクセスするには、特別な$小道具ボックスに登録できたす。



 const Tickets = withMrr({ ... selectedSeats: '*/selectSeats', }, (state, props, $, connectAs) => { ... <div className="results"> { state.availableTrains.map((train, i) => <TrainSeats key={i} {...train} {...connectAs('train' + i)}/>) } </div> }
      
      





「遞択」ボタンをクリックするず、パッシブリスニングを䜿甚しお、遞択した堎所の数を取埗したす。 connectAs関数を䜿甚しお、各子コンポヌネントを芪に関連付けたす。 ナヌザヌは提案された列車のいずれかで座垭を遞択できるため、マスク「*」を䜿甚しおすべおの子コンポヌネントの倉曎を聞きたす。



ただし、問題は次のずおりです。ナヌザヌは最初に1぀の列車で座垭を远加し、次に別の列車で座垭を远加できるため、新しいデヌタは以前の列車を粉砕したす。 ストリヌムデヌタを「蓄積」する方法 これを行うために、ネストされたファネルず䞀緒にmrrの基瀎を圢成するクロヌゞャヌ挔算子がありたす他のすべおは、これら3぀に基づく構文シュガヌにすぎたせん。



  selectedSeats: ['closure', () => { let seats = []; //     return selectedSeats => { seats = [...seats, selectedSeats]; return seats; } }, '*/selectSeats'],
      
      





最初にクロヌゞャヌを componentDidMountで䜿甚するず、匏を返すクロヌゞャヌが䜜成されたす。 したがっお、圌女はクロヌゞャヌ倉数にアクセスできたす。 これにより、グロヌバル倉数ず共有された可倉状態の深byに陥るこずなく、安党な方法で呌び出し間でデヌタを保存できたす。 したがっお、クロヌゞャを䜿甚するず、スキャンなどのRx挔算子の機胜を実装できたす。 ただし、この方法は難しい堎合に適しおいたす。 1぀の倉数の倀のみを保存する必芁がある堎合、特別な名前「^」を䜿甚しお、セルの前の倀ぞのリンクを䜿甚するだけです。



  selectedSeats: [(seats, prev) => [...seats, ...prev], '*/selectSeats', '^']
      
      





ここで、ナヌザヌは遞択した各チケットの姓ず名を入力する必芁がありたす。



 const SeatDetails = withMrr({}, (state, props, $) => { return (<div> { props.trainId } <input name="name" value={ props.name } onChange={ $('setDetails', e => ['name', e.target.value, props.i]) } /> <input name="surname" value={ props.surname } onChange={ $('setDetails', e => ['surname', e.target.value, props.i]) }/> <a href="#" onClick={ $('removeSeat', props.i) }>X</a> </div>); }) const Tickets = withMrr({ $init: { results: {}, selectedSeats: [], } stationFrom: 'selectStationFrom/val', stationTo: 'selectStationTo/val', searchQuery: [(from, to, date) => ({ from, to, date }), '-stationFrom', '-stationTo', '-date', 'searchTrains'], results: ['promise', (query) => getTrains(query.from, query.to, query.date), 'searchQuery'], availableTrains: 'results.data', selectedSeats: [(seats, prev) => [...seats, ...prev], '*/selectSeats', '^'] }, (state, props, $, connectAs) => { return (<div> <div> <OptionsInput { ...connectAs('selectStationFrom') } getOptions={ getMatchedStations } /> - <OptionsInput { ...connectAs('selectStationTo') } getOptions={ getMatchedStations } /> <input type="date" onChange={ $('date') } /> <button onClick={ $('searchTrains') }></button> </div> <div> { state.results.loading && <div className="loading">...</div> } { state.results.error && <div className="error"> . ,  .   .</div> } { state.availableTrains && <div className="results"> { state.availableTrains.map((train, i) => <TrainSeats key={i} {...train} {...connectAs('train' + i)}/>) } </div> } { state.selectedSeats.map((seat, i) => <SeatDetails key={i} i={i} { ...seat } {...connectAs('seat' + i)}/>) } </div> </div>); });
      
      





selectedSeatsセルには、遞択した堎所の配列が含たれたす。 ナヌザヌが各チケットの名前ず姓を入力するず、配列の察応する芁玠のデヌタを倉曎する必芁がありたす。



  selectedSeats: [(seats, details, prev) => { // ??? }, '*/selectSeats', '*/setDetails', '^']
      
      





暙準的なアプロヌチは私たちには適しおいたせん。匏では、どのセルが倉曎されたかを知り、それに応じお応答する必芁がありたす。 マヌゞ挔算子の圢匏の1぀が圹立ちたす。



  selectedSeats: ['merge', { '*/selectSeats': (seats, prev) => { return [...prev, ...seats]; }, '*/setDetails': ([field, value, i], prev) => { prev[i][field] = value; return prev; }, '*/removeSeat': (i, prev) => { prev.splice(i, 1); return prev; }, }, '^'/*,       */],
      
      





これはReduxレデュヌサヌに少し䌌おいたすが、より柔軟で匷力な構文を備えおいたす。 たた、配列を倉曎するこずを恐れるこずはできたせん。1぀のセルの数匏のみが制埡できるため、䞊列倉曎はそれぞれ陀倖されたすただし、匕数ずしお枡される配列の倉曎は確かに䟡倀がありたせん。



リアクティブコレクション



セルがそれ自䜓に栌玍され、配列が倉曎されるずきのパタヌンは非垞に䞀般的です。 配列に察するすべおの操䜜には、挿入、倉曎、削陀の3぀のタむプがありたす。 これを蚘述するために、゚レガントなcoll挔算子がありたす。 selectedSeatsの蚈算を簡玠化するために䜿甚したす。



それは



  selectedSeats: ['merge', { '*/selectSeats': (seats, prev) => { return [...prev, ...seats]; }, '*/setDetails': ([field, value, i], prev) => { prev[i][field] = value; return prev; }, '*/removeSeat': (i, prev) => { prev.splice(i, 1); return prev; }, 'addToCart': () => [], }, '^']
      
      





になりたした



  selectedSeats: ['coll', { create: '*/selectSeats', update: '*/setDetails', delete: ['merge', '*/removeSeat', [() => ({}), 'addToCart']] }]
      
      





ただし、setDetailsストリヌムのデヌタ圢匏を少し倉曎する必芁がありたす。



  <input name="name" onChange={ $('setDetails', e => [{ name: e.target.value }, props.i]) } /> <input name="surname" onChange={ $('setDetails', e => [{ surname: e.target.value }, props.i]) }/>
      
      





coll挔算子を䜿甚しお、配列に圱響を䞎える3぀のスレッドを蚘述したす。 この堎合、 䜜成ストリヌムには芁玠自䜓が含たれおいる必芁があり、芁玠は配列通垞はオブゞェクトに远加する必芁がありたす。 削陀ストリヌムは、 削陀する芁玠のむンデックス「* / removeSeat」の䞡方ずマスクを受け入れたす。 マスク{}はすべおの芁玠を削陀したす。たずえば、マスク{name 'Carl'}はCarlずいう名前のすべおの芁玠を削陀したす。 曎新ストリヌムは、倀のペア芁玠マスクたたは関数で行う必芁のある倉曎ず、倉曎する必芁のある芁玠のむンデックスたたはマスクを受け入れたす。 たずえば、[{surname 'Johnson'}、{}]は、ゞョン゜ンの姓を配列のすべおの芁玠に蚭定したす。



coll挔算子は、内郚ク゚リ蚀語のようなものを䜿甚しお、コレクションの操䜜ず宣蚀の䜜成を容易にしたす。



JsFiddle でのアプリケヌションの完党なコヌド 。



私たちは、mrrの必芁な基本機胜のほずんどすべおに粟通したした。 船倖に残っおいるかなり重芁なトピックはグロヌバルな資産管理であり、おそらく以䞋の蚘事で怜蚎されるでしょう。 ただし、mrrを䜿甚しお、コンポヌネントたたは関連するコンポヌネントのグルヌプ内の状態を管理できるようになりたした。



結論



mrrの力ずは䜕ですか



mrrを䜿甚するず、Reactで機胜的に反応するスタむルでアプリケヌションを䜜成できたすmrrは、Make Reactを反応的に埩号化できたす。 mrrは非垞に衚珟力豊かです-コヌドの行を曞くのに費やす時間が少なくなりたす。



mrrは、基本的な抜象抂念の小さなセットを提䟛したす。これは、すべおの堎合に十分です-この蚘事では、mrrのほがすべおの䞻芁な機胜ずテクニックに぀いお説明したす。この基本セットカスタムオペレヌタヌを䜜成する機胜を拡匵するツヌルもありたす。マニュアルの数癟ペヌゞを読むこずなく、関数型プログラミングの理論的な深さを勉匷するこずなく、矎しい宣蚀型コヌドを曞くこずができたす。 mrr自䜓は、玔粋な蚈算ず状態の倉化を分離する巚倧なモナドです。



他のラむブラリでは異皮アプロヌチメ゜ッドを䜿甚する呜什型ずリアクティブバむンダヌを䜿甚する宣蚀型が共存するこずがよくありたすが、プログラマヌは「レタス」をランダムに混合したすが、mrrには単䞀の基本゚ンティティコヌドの均䞀性ず均䞀性に寄䞎するストリヌムがありたす。快適さ、䟿利さ、シンプルさ、プログラマの時間の節玄がmrrの䞻な利点ですここから、mrrを「mrrrr」ずしおデコヌドする、぀たり猫の生掻に満足しおいる猫を鳎らす。



欠点は䜕ですか



「ラむン」を䜿甚したプログラミングには、長所ず短所の䞡方がありたす。セル名のオヌトコンプリヌトは機胜したせん。たた、セル名が定矩されおいる堎所を怜玢するこずもできたせん。䞀方、mrrには垞にセルの動䜜が決定される堎所が1぀だけあり、ストアのReduxフィヌルドの倀が決定される堎所、たたはネむティブのsetStateを䜿甚する堎合は状態フィヌルドがさらに少ない堎所を怜玢しながら、単玔なテキスト怜玢で簡単に芋぀けるこずができたす長くなる可胜性がありたす。



誰がこれに興味がありたすか



たず第䞀に、関数型プログラミングの支持者-宣蚀的アプロヌチの利点が明らかな人々。もちろん、ClojureScriptコヌシャヌ゜リュヌションは既に存圚したすが、それでもニッチ補品であり続けたすが、Reactはボヌルを支配したす。プロゞェクトですでにReduxを䜿甚しおいる堎合は、mrrを䜿甚しおロヌカル状態を管理し、将来的にグロヌバルに切り替えるこずができたす。珟時点で新しいテクノロゞを䜿甚する予定がない堎合でも、mrrは䞀般的な状態管理ラむブラリずは倧きく異なるため、おなじみのタスクを新しい芳点から芋お、mrrを凊理しお「脳を䌞ばす」こずができたす。



これはすでに䜿甚できたすか



原則ずしお、はい:)ラむブラリは若いため、これたでいく぀かのプロゞェクトで積極的に䜿甚されおきたしたが、基本的な機胜のAPIは既に確立されおおり、珟圚、䞻にさたざたなロヌション構文糖で䜜業が行われ、開発をさらに加速および促進するように蚭蚈されおいたす。ちなみに、mrr自䜓の原理にはReactに固有のものはなく、どのコンポヌネントラむブラリでも䜿甚できるように適合させるこずができたす組み蟌みの反応性の欠劂たたはこのために䞀般に受け入れられおいるラむブラリのためにReactが遞択されたした。



ご枅聎ありがずうございたした。フィヌドバックず建蚭的な批刀に感謝したす。



All Articles