ステヌトマシンずWebアプリケヌション開発

2018幎が来お、アプリケヌションを䜜成する倚くの玠晎らしい方法が芋぀かりたしたが、フロント゚ンド開発者の無数の軍隊は、Webプロゞェクトのシンプルさず柔軟性のためにただ戊い続けおいたす。 圌らは、゚ラヌのない゜フトりェアアヌキテクチャを芋぀けお、迅速か぀効率的に䜜業を行えるようにするずいう、倧切な目暙を達成するために、毎月費やしおいたす。 私はこれらの開発者の䞀人です。 勝぀チャンスを䞎えおくれる面癜いものを芋぀けるこずができた。


ReactやReduxなどのツヌルにより、Web開発は正しい方向に倧きな䞀歩を螏み出すこずができたした。 ただし、それらだけでは倧芏暡なアプリケヌションを䜜成するには䞍十分です。 Webアプリケヌションのクラむアント偎郚分の開発状況は、ステヌトマシンの䜿甚を倧幅に改善できるようです。 それらに぀いおは、この資料で説明したす。 ずころで、おそらくこれらのマシンのいく぀かを既に構築しおいるが、それに぀いおはただ知らない。

ステヌトマシンの玹介


ステヌトマシンは、蚈算の数孊モデルです。 これは抜象的な抂念であり、マシンはさたざたな状態を持぀こずができたすが、ある時点ではそのうちの1぀だけにずどたりたす。 最も有名なステヌトマシンはチュヌリングマシンだず思いたす。 これは、無制限の数の状態を持぀マシンです。぀たり、無制限の数の状態を持぀こずができたす。 ほずんどの堎合、状態の数が有限であるため、チュヌリングマシンは最新のむンタヌフェむス開発のニヌズを十分に満たしおいたせん。 そのため、状態の数が限られおいるマシン、たたはしばしば呌ばれるように、有限状態マシンは、私たちにずっおより良いです。 これはMily マシンずMooreマシンです。

2぀の違いは、ムヌアオヌトマトンが以前の状態のみに基づいお状態を倉曎するこずです。 ただし、ネットワヌク䞊で行われるナヌザヌのアクションやプロセスなど、倚くの倖郚芁因がありたす。぀たり、ムヌアマシンも私たちには適しおいないずいうこずです。 私たちが探しおいるのは、Milesマシンに非垞によく䌌おいたす。 この有限状態マシンには初期状態があり、その埌、入力デヌタずその珟圚の状態に基づいお、新しい状態になりたす。

ステヌトマシンの動䜜を説明する最も簡単な方法の1぀は、回転匏改札機ずの類掚を通じおそれを考慮するこずです。 限られた状態のセットがありたすそれは閉じおいるか開いおいるこずができたす。 私たちの回転匏改札口は、特定の゚リアぞの入り口をブロックしたす。 圌に3぀のスラットを備えたドラムず、お金を受け取るメカニズムを持たせおください。 コむンをコむンアクセプタヌに降ろすず閉じたタヌンスタむルを通過できたす。コむンアクセプタヌはデバむスを開いた状態にし、タヌンスタむルを通過するためにバヌを抌したす。 改札口を通過した埌、再び閉じたす。 以䞋に、これらの状態、および可胜な入力信号ず状態間の遷移を瀺す簡単な図を瀺したす。


回転匏改札口の初期状態は「クロヌズ」ロックです。 䜕回圌のバヌを抌しおも、圌は閉じたたたになりたす。 ただし、コむンをドロップするず、タヌンスタむルは「オヌプン」ロック解陀状態になりたす。 珟時点では、回転匏改札口は開いたたたなので、別のコむンは䜕も倉曎したせん。 䞀方、タヌンスタむルバヌを抌すこずは理にかなっおおり、それを通り抜けるこずができたす。 さらに、このアクションは、有限状態マシンを初期の「閉じた」状態に移行したす。

回転匏改札口を制埡する唯䞀の関数を実装する必芁がある堎合は、おそらく2぀の匕数に焊点を圓おる必芁がありたす。これは珟圚の状態ずアクションです。 Reduxを䜿甚しおいる堎合は、これに慣れおいるかもしれたせん。 これは、珟圚の状態を取埗し、アクションペむロヌドに基づいお次の状態を決定する既知のレデュヌサヌ関数に䌌おいたす。 レデュヌサヌは、ステヌトマシンのコンテキストにおける遷移です。 実際、䜕らかの方法で倉曎できる状態を持぀アプリケヌションは、ステヌトマシンず呌ばれたす。 実際、これらすべおが䜕床も䜕床も手動で実装されおいたす。

ステヌトマシンの長所は䜕ですか


職堎ではReduxを䜿甚しおいたすが、これは私たちにぎったりです。 しかし、気に入らない点に気づき始めたした。 䜕かが奜きではないからずいっお、それが機胜しないずいう意味ではありたせん。 これはすべお、プロゞェクトに耇雑さを远加し、より倚くのコヌドを曞くこずを䜙儀なくされるずいう事実に関するものです。 サヌドパヌティのプロゞェクトを開始し、そこで実隓の䜙地があったので、ReactずReduxでの開発アプロヌチを再考するこずにしたした。 気になっおいるこずに぀いおメモを取り始め、ステヌトマシンの抜象化がこれらの問題のいく぀かを解決する可胜性が高いこずに気付きたした。 ビゞネスに取り掛かり、JavaScriptでステヌトマシンを実装する方法を芋おみたしょう。

簡単な問題を解決したす。 サヌバヌAPIからデヌタを取埗し、ナヌザヌに衚瀺する必芁がありたす。 最初のステップは、問題に぀いお考えるずき、遷移ではなく状態の芳点から考える方法を理解するこずです。 ステヌトマシンに移る前に、䜜成したいものがどのように芋えるかに぀いお、高レベルで説明したす。



ここで、問題を分析し、盎線的に考え、実際、最終結果ぞのすべおの可胜な経路をカバヌしようずしたす。 あるステップは別のステップに぀ながり、次のステップは別のステップに぀ながりたす。 コヌドでは、これは分岐挔算子ずしお衚珟できたす。 ナヌザヌずシステムのアクションに基づいお構築されたプログラムで思考実隓を行っおみたしょう。

ナヌザヌがボタンを2回クリックする状況はどうですか サヌバヌからの応答を埅っおいる間にナヌザヌがボタンをクリックするずどうなりたすか 芁求は成功したが、デヌタが砎損した堎合、システムはどのように動䜜したすか
このような状況を凊理するには、䜕が起こっおいるのかを瀺すさたざたなフラグが必芁になるでしょう。 フラグの存圚は、 ifの数の増加を意味し、より耇雑なアプリケヌションでは、競合の数の増加を意味したす。


それは、移行期に考えるからです。 プログラムの倉曎が正確にどのように発生するか、およびそれらが発生する順序に焊点を圓おたす。 代わりに、アプリケヌションのさたざたな状態に焊点を合わせるず、すべおが倧幅に簡玠化されたす。 いく぀の条件がありたすか 圌らのむンプットは䜕ですか 同じ䟋を䜿甚したす。


ここでは、同じプロセスに぀いお説明したしたが、珟圚は状態ず入力デヌタを䜿甚しおいたす。


これにより、ロゞックが簡玠化され、予枬しやすくなりたした。 さらに、䞊蚘の問題のいく぀かを解決したした。 マシンがfetching状態にあるずき、ボタンのマりスクリックに関連するむベントを受け入れないこずに泚意しおください。 したがっお、ナヌザヌがボタンをクリックしおも、マシンはfetching状態にあるずきにこのアクションに反応するように構成されおいないため、䜕も起こりたせん。 このアプロヌチにより、コヌドロゞックの予期しない分岐が自動的に排陀されたす。

これは、テスト䞭により少ないコヌドをカバヌする必芁があるこずを意味したす。 さらに、統合テストなどの䞀郚のタむプのテストは自動化できたす。 このアプロヌチを䜿甚するず、アプリケヌションの実行内容を非垞に明確に理解でき、定矩枈みの状態ず遷移を通過しおステヌトメントを生成するスクリプトを䜜成できるず考えおください。 これらのステヌトメントは、可胜性のある各状態に到達したこず、たたは特定の遷移シヌケンスを完了したこずを蚌明できたす。

実際、どの状態が必芁か、どの状態を持っおいるかを知っおいるので、可胜なすべおの状態を曞き出す方が、可胜なすべおの遷移を曞き出すよりも簡単です。 ずころで、ほずんどの堎合、状態はアプリケヌションの機胜のロゞックを蚘述したす。 しかし、トランゞションに぀いお話す堎合、それらの意味はしばしば䜜業の開始時に䞍明です。 プログラムの゚ラヌは、アプリケヌションがこれらのアクション甚に蚭蚈されおいない状態にあるずきにアクションが実行されるずいう事実の結果です。 さらに、アプリケヌションが適切な状態にある堎合でも、アクションが間違った時間に実行される可胜性がありたす。 このようなアクションにより、アプリケヌションは䞍明な状態になり、これによりプログラムが無効になるか、正しく動䜜しないずいう事実に぀ながりたす。 もちろん、必芁ありたせん。 ステヌトマシンは、このような問題に察する優れた察策です。 これにより、発生する可胜性のある状況を明確に指定するこずなく、発生する可胜性のある境界を蚭定するため、未知の状態に到達するこずを防ぎたす。 ステヌトマシンの抂念は、単方向のデヌタストリヌムに適しおいたす。 䞀緒に、コヌドの耇雑さを軜枛し、システムが特定の状態になった方法に関する質問に明確な回答を提䟛したす。

JavaScriptを䜿甚しおステヌトマシンを䜜成する


十分な話-それはプログラムする時間です。 同じ䟋を䜿甚したす。 䞊蚘のリストに基づいお、次のコヌドから始めたしょう。

 const machine = { 'idle': {   click: function () { ... } }, 'fetching': {   success: function () { ... },   failure: function () { ... } }, 'error': {   'retry': function () { ... } } } 

状態はオブゞェクトによっお衚され、可胜な入力状態信号はオブゞェクトのメ゜ッドによっお衚されたす。 ただし、初期状態はここにはありたせん。 䞊蚘のコヌドを倉曎しお、次の圢匏にしたす。

 const machine = { state: 'idle', transitions: {   'idle': {     click: function() { ... }   },   'fetching': {     success: function() { ... },     failure: function() { ... }   },   'error': {     'retry': function() { ... }   } } } 

意味のある状態をすべお特定したら、入力信号を送信しおシステムの状態を倉曎する準備が敎いたす。 これを行うには、次の2぀の補助的な方法を䜿甚したす。

 const machine = { dispatch(actionName, ...payload) {   const actions = this.transitions[this.state];   const action = this.transitions[this.state][actionName];   if (action) {     action.apply(machine, ...payload);   } }, changeStateTo(newState) {   this.state = newState; }, ... } 

dispatch機胜は、珟圚の状態の遷移の䞭に、指定された名前のアクションがあるかどうかを確認したす。 その堎合、圌女はこのアクションを呌び出し、呌び出し䞭に転送されたデヌタを圌に枡したす。 さらに、 actionハンドラはmachineをコンテキストずしお呌び出されるため、 this.dispatch(<action>)を䜿甚しお別のアクションをthis.dispatch(<action>)しthis.dispatch(<action>) this.changeStateTo(<new state>)を䜿甚しお状態を倉曎したりできたす。

この䟋のナヌザヌパスに埓っお、ディスパッチする必芁がある最初のアクションはclickです。 このアクションのハンドラヌは次のようになりたす。

 transitions: { 'idle': {   click: function () {     this.changeStateTo('fetching');     service.getData().then(       data => {         try {           this.dispatch('success', JSON.parse(data));         } catch (error) {           this.dispatch('failure', error)         }       },       error => this.dispatch('failure', error)     );   } }, ... } machine.dispatch('click'); 

最初に、マシンの状態をfetchingたす。 次に、サヌバヌぞのリク゚ストを実行したす。 promiseを返すgetDataメ゜ッドを持぀サヌビスがあるずしたす。 このプロミスが解決され、デヌタが正垞に解析された埌、 succesむベントをディスパッチしたす。

すべおが正垞に進行しおいる間。 次に、 successアクションずfailureアクションを実装し、 fetchingステヌタスの入力を蚘述する必芁がありたす。

 transitions: { 'idle': { ... }, 'fetching': {   success: function (data) {     //       this.changeStateTo('idle');   },   failure: function (error) {     this.changeStateTo('error');   } }, ... } 

以前のプロセスに぀いお考える必芁から自分を救ったこずに泚意しおください。 ナヌザヌがボタンをクリックするこずや、HTTPリク゚ストで䜕が起こるかは気にしたせん。 アプリケヌションがfetching状態にあるこずはわかっおおり、これら2぀のアクションのみが衚瀺されるこずを期埅しおいたす。 これは、分離しお動䜜する新しいアプリケヌション゚ンゞンを䜜成するこずに少し䌌おいたす。

最埌に察凊する必芁があるのは、 error状態です。 ここでコヌドを䜜成しお再詊行を実装するず非垞に䟿利です。その結果、゚ラヌが発生した埌、アプリケヌションを回埩できたす。

 transitions: { 'error': {   retry: function () {     this.changeStateTo('idle');     this.dispatch('click');   } } } 

ここでは、 clickハンドラヌで既に蚘述されおいるコヌドをコピヌする必芁がありclick 。 これを回避するには、䞡方のアクションで䜿甚可胜な関数ずしおハンドラヌを宣蚀するか、最初にidle状態に切り替えおからclickアクションを自分でディスパッチする必芁がありclick 。

動䜜状態マシンの完党な䟋は、CodePenプロゞェクトにありたす。

ラむブラリを䜿甚しおステヌトマシンを管理する


ステヌトマシンテンプレヌトは、React、Vue、Angularのいずれを䜿甚しおも機胜したす。 前のセクションで芋たように、玔粋なJSにステヌトマシンを実装するこずはそれほど困難ではありたせん。 ただし、これを特殊なラむブラリに委任するず、プロゞェクトの柔軟性が向䞊したす。 ステヌトマシンの実装に適したラむブラリの䟋には、 Machina.jsおよびXStateが含たれたす。 ただし、この蚘事では、ステヌトマシンの抂念を実装するReduxに䌌たラむブラリであるStentに぀いお説明したす。

ステントは、ステヌトマシンコンテナの実装です。 このラむブラリは、ReduxおよびRedux-Sagaプロゞェクトからのいく぀かのアむデアに埓いたすが、私の意芋では、䜿いやすく、テンプレヌトによる制玄が少なくなりたす。 最初にプロゞェクトのドキュメントを䜜成し、次にコヌドを䜜成するずいう事実に基づいたアプロヌチを䜿甚しお開発されおいたす。 このアプロヌチに続いお、APIの蚭蚈のみを数週間行いたした。 ラむブラリを自分で曞いたので、ReduxおよびFluxアヌキテクチャを䜿甚しお遭遇した問題を修正する機䌚がありたした。

ステントでのステヌトマシンの䜜成


ほずんどの堎合、アプリケヌションは倚くの機胜を実行したす。 その結果、1台のマシンだけを実行するこずはできたせん。 したがっお、ステントを䜿甚するず、必芁な数のマシンを䜜成できたす。

 import { Machine } from 'stent'; const machineA = Machine.create('A', { state: ..., transitions: ... }); const machineB = Machine.create('B', { state: ..., transitions: ... }); 

埌でMachine.getメ゜ッドを䜿甚しおこれらのマシンにアクセスできたす。

 const machineA = Machine.get('A'); const machineB = Machine.get('B'); 

マシンをレンダリングロゞックに接続する


私の堎合のレンダリングはReactツヌルを䜿甚しお行われたすが、他のラむブラリを䜿甚するこずもできたす。 すべおは、レンダリングを開始するコヌルバックを呌び出すこずです。 私が䜜成したラむブラリの最初の機胜の1぀は、 connect機胜でした。

 import { connect } from 'stent/lib/helpers'; Machine.create('MachineA', ...); Machine.create('MachineB', ...); connect() .with('MachineA', 'MachineB') .map((MachineA, MachineB) => {   ...      }); 

どのマシンを操䜜したいかをシステムに通知し、名前を瀺したす。 mapメ゜ッドに枡すコヌルバックはすぐに呌び出され、これは1回行われたす。 その埌、いずれかのマシンの状態が倉化するたびに呌び出されたす。 これがレンダリング関数を呌び出す堎所です。 この堎所では、接続されたマシンに盎接アクセスできるため、マシンずそのメ゜ッドの珟圚の状態を取埗できたす。 このラむブラリには、䞀床だけ呌び出す必芁があるコヌルバックを凊理するために䜿甚されるmapOnceメ゜ッドず、この最初の1回限りのコヌルバックの実行をスキップするためのmapSilentたす。

䟿宜䞊、Reactずの統合のために補助関数が゚クスポヌトされおいたす。 これは、 接続mapStateToProps Reduxコンストラクトに非垞に䌌おいたす。

 import React from 'react'; import { connect } from 'stent/lib/react'; class TodoList extends React.Component { render() {   const { isIdle, todos } = this.props;   ... } } // MachineA  MachineB -  ,  //    Machine.create export default connect(TodoList) .with('MachineA', 'MachineB') .map((MachineA, MachineB) => {   isIdle: MachineA.isIdle,   todos: MachineB.state.todos }); 

ステントはコヌルバックし、オブゞェクトを受け取るこずを期埅したす。 ぀たり、Reactコンポヌネントにpropsずしお送信されるオブゞェクト。

ステントのコンテキストにおける状態ずは䜕ですか


これたでのずころ、状態は単玔な文字列です。 残念ながら、珟実の䞖界では、通垞の文字列以倖の状態で保存する必芁がありたす。 それが、ステント状態がプロパティを持぀オブゞェクトである理由です。 予玄されおいるプロパティはnameのみです。 それ以倖はすべおアプリケヌション固有のデヌタです。 䟋

 { name: 'idle' } { name: 'fetching', todos: [] } { name: 'forward', speed: 120, gear: 4 } 

Stentの私の経隓では、状態オブゞェクトが倧きくなりすぎるず、おそらくこれらの远加プロパティを凊理できる別の状態マシンが必芁になるこずがわかりたす。 さたざたな状態を特定するには時間がかかりたすが、これは管理が容易なアプリケヌションを䜜成する䞊で倧きな前進だず思いたす。 これは、システムの動䜜を事前に蚈画し、将来のアクションのためのスペヌスを準備する詊みのようなものです。

ステヌトマシンを操䜜する


材料の冒頭に瀺した䟋ずほが同じ方法で、ステントを䜿甚する堎合、マシンの可胜な最終状態を蚭定し、可胜な入力信号を蚘述する必芁がありたす。

 import { Machine } from 'stent'; const machine = Machine.create('sprinter', { state: { name: 'idle' }, //   transitions: {   'idle': {     'run please': function () {       return { name: 'running' };     }   },   'running': {     'stop now': function () {       return { name: 'idle' };     }   } } }); 

runアクションをrunする初期状態idleがありたす。 マシンがrunning状態になったら、 stopアクションを開始しお、マシンをidle状態に戻すこずができたす。

䞊蚘の䟋のヘルパヌ関数dispatchおよびchangeStateTo思い出しおください。 ステントは同じ機胜を提䟛したすが、ラむブラリ内に隠されおいるため、自分で察凊する必芁はありたせん。 䟿宜䞊、 transitionsプロパティに基づいお、Stentは以䞋を生成したす。


その結果、この䟋では次の構成が利甚できたす。

 machine.isIdle(); //   machine.isRunning(); //   machine.runPlease(); //   machine.stopNow(); //   

自動生成されたメ゜ッドをサヌビスconnect機胜ず組み合わせるこずにより、既補の゜リュヌションを思い付くこずができたす。 ナヌザヌは、マシンの入力ず状態の倉化に぀ながるアクションに圱響を䞎えたす。 状態の倉化により、 connect枡されたマッピング関数が呌び出され、状態の倉化に関する通知を受け取りたす。 次に、デヌタが画面に出力されたす。

入力デヌタずアクションハンドラヌ


おそらく、この䟋で最も重芁なのはアクションハンドラヌです。 これは、システムが入力デヌタおよび倉曎された状態にどのように反応するかを説明するため、ほずんどのアプリケヌションロゞックを蚘述する堎所です。 Reduxの蚭蚈䞭に行われた最も成功したアヌキテクチャの決定は、reducer関数の䞍倉性ず単玔さであるず時々思えたす 。 本質的に、ステントアクションハンドラヌは同じものです。 ハンドラヌは珟圚の状態ずアクションに関連付けられたデヌタを受け取り、その埌新しい状態を返す必芁がありたす。 ハンドラヌが䜕も返さない堎合 undefined 、マシンの状態は倉曎されたせん。

 transitions: { 'fetching': {   'success': function (state, payload) {     const todos = [ ...state.todos, payload ];     return { name: 'idle', todos };   } } } 

リモヌトサヌバヌからデヌタをダりンロヌドするずしたす。 これを行うには、リク゚ストを実行し、マシンをfetching状態にしたす。 サヌバヌからデヌタが到着するずすぐに、 successむベントが発生successたす。

 machine.success({ label: '...' }); 

その埌、 idle状態に戻り、䞀郚のデヌタをtodos配列ずしお保存したす。 アクションハンドラを構成するためのオプションがいく぀かありたす。 最初の最も単玔なケヌスは、新しい状態になる単玔な文字列での䜜業です。

 transitions: { 'idle': {   'run': 'running' } } 

ここに瀺されおいるのは、 run()アクションを䜿甚した{ name: 'idle' }状態から{ name: 'running' }状態ぞの遷移です。 このアプロヌチは、状態に远加のデヌタがなく、状態間の同期遷移が䜿甚される堎合に圹立ちたす。 したがっお、状態オブゞェクトに他の䜕かが栌玍されおいる堎合、状態間のこのような遷移は、そのような远加デヌタを砎壊したす。 同様に、状態オブゞェクトを盎接枡すこずができたす。

 transitions: { 'editing': {   'delete all todos': { name: 'idle', todos: [] } } } 

ここでは、 deleteAllTodosアクションを䜿甚しお、 editing状態からidleぞの移行を芳察できたす。

ハンドラヌ関数は既に芋おおり、アクションハンドラヌの最埌のバヌゞョンはゞェネレヌタヌ関数です。 Redux-Sagaプロゞェクトは、このメカニズムのむデオロギヌ的刺激源になりたした。次のようになりたす。

 import { call } from 'stent/lib/helpers'; Machine.create('app', { 'idle': {   'fetch data': function * (state, payload) {     yield { name: 'fetching' }     try {       const data = yield call(requestToBackend, '/api/todos/', 'POST');       return { name: 'idle', data };     } catch (error) {       return { name: 'error', error };     }   } } }); 

ゞェネレヌタヌの経隓がない堎合、䞊蚘のコヌドフラグメントは少し䞍思議に芋えるかもしれたせん。 ただし、JavaScriptゞェネレヌタヌは匷力なツヌルです。 圌らの助けを借りお、アクションハンドラを䞀時停止し、状態を数回倉曎し、非同期メカニズムを凊理できたす。

発電機実隓


Redux-Sagaに初めお䌚ったずき、非同期操䜜をサポヌトするための非垞に耇雑な方法を提瀺するこずにしたした。 実際、これはコマンドテンプレヌトの非垞に機知に富んだ実装です。 このテンプレヌトの䞻な利点は、メカニズムずその実際の実装の課題を共有しおいるこずです。

぀たり、システムに必芁なこずを䌝えたすが、これがどのように行われるべきかに぀いおは話したせん。 Matt Hicks による䞀連の資料は、これを理解するのに圹立ちたした。 同じアむデアをステントにもたらしたした。 システムに制埡を移し、必芁なものを通知したすが、実際には行いたせん。 アクションが完了するず、制埡が戻りたす。

珟時点でシステムに転送できるものは次のずおりです。


䞊蚘の䟋を瀺す関数を次に瀺したす。

 const fireHTTPRequest = function () { return new Promise((resolve, reject) => {   // ... }); } ... transitions: { 'idle': {   'fetch data': function * () {     yield 'fetching'; //    { name: 'fetching' }     yield { name: 'fetching' }; //   ,        //       //  getTheData  checkForErrors     const [ data, isError ] = yield wait('get the data', 'check for errors');     //   ,     //  fireHTTPRequest     const result = yield call(fireHTTPRequest, '/api/data/users');     return { name: 'finish', users: result };   } } } 

, , , . , Stent .

Redux Stent


▍


Redux ( Flux) , . , , . , . , , , .

Stent . :

 const machine = Machine.create('todo-app', { state: { name: 'idle', todos: [] }, transitions: {   'idle': {     'add todo': function (state, todo) {       ...     }   } } }); machine.addTodo({ title: 'Fix that bug' }); 

machine.addTodo , . , : , . React addToDo . , . . .

▍


, Redux . Redux, , . , , , ? — Redux? , , , - . , , . , - , .

, ? ?

Redux, , . , . Stent , , . 䟋

 const machine = Machine.create('app', { state: { name: 'idle' }, transitions: {   'idle': {     'run': 'running',     'jump': 'jumping'   },   'running': {     'stop': 'idle'   } } }); //   machine.run(); //     , //       // running       stop. machine.jump(); 

, .


Redux, Flux, . , Redux-, , , , . , , , , , . , , , .

たずめ


, — , . , , , . . , , , — . , — . — , — . - , .

芪愛なる読者 ?

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


All Articles