この記事は、Vildan Softicによって査読されました。 SetePointのコンテンツを完璧にしてくれたSetePointのすべてのピアレビューアに感謝します!
私は、ゼロから始めて、すべてがどのように機能するかを理解するのが好きな開発者のようなものです。私はこれが自分自身に(不必要な)ワークロードをもたらすことを知っていますが、特定のフレームワーク、ライブラリ、またはモジュールの背後にあるメカニズムを理解し理解するのに役立ちます。
最近、私は再びこの瞬間を経験し、ReduxとPure JavaScriptを使用してWebアプリケーションの開発を開始しました。この記事では、アプリケーション構造の概要を説明し、早期(最終的に失敗した)反復を調べてから、最終的に選択したソリューションと学んだことを見たいと思います。
Reactは、ユーザーインターフェイスを構築するためにFacebookが作成したコンポーネントベースのオープンソースライブラリです。 Reactは単なるビューレイヤーですが(
問題のアプリケーションは、いくつかの異なるビューを持つモバイルファーストテトリスクローンです。実際のゲームロジックはReduxで行われますが、オフライン機能はLocalStorageおよびカスタムビュー処理によって提供されます。リポジトリはGitHubで見つけることができますが、アプリはまだアクティブな開発中に開発されており、開発中にこの記事を書きました。
ReduxおよびReact Projectsで一般的なフォルダー構造を採用することにしました。これは、さまざまな設定で機能する論理構造です。このトピックには多くのバリエーションがあり、ほとんどのプロジェクトはわずかに異なりますが、全体的な構造は同じです。
src/scripts/
<code>actions/ ├── game.js ├── score.js └── ... components/ ├── router.js ├── pageControls.js ├── canvas.js └── ... constants/ ├── game.js ├── score.js └── ... reducers/ ├── game.js ├── score.js └── ... store/ ├── configureStore.js ├── connect.js └── index.js utils/ ├── serviceWorker.js ├── localStorage.js ├── dom.js └── ... index.js worker.js</code>
私のタグは別のディレクトリに分離され、単一のindex.htmlファイルによってレンダリングされることになります。この構造は、スクリプト/コードベース全体で一貫したアーキテクチャを維持するために類似しています。
src/markup/
<code>layouts/ └── default.html partials/ ├── back-button.html └── meta.html pages/ ├── about.html ├── settings.html └── ... index.html</code>
ストレージにアクセスするには、アプリケーションのすべてのインスタンスに1回作成して渡す必要があります。ほとんどのフレームワークは、ある種の依存関係噴射コンテナを使用しているため、フレームワークユーザーとして自分でソリューションを作成する必要はありません。しかし、自分のソリューションを使用するとき、どうすればすべてのコンポーネントで利用できるようにすることができますか?
私の最初の反復は失敗しました。なぜこれが良いアイデアだと思うのかわかりませんが、ストレージを独自のモジュール(Scripts/Store/Index.js)に入れて、その後、残りのアプリケーションでインポートできます。私はそれを後悔し、すぐに円形の依存関係を扱いました。問題は、コンポーネントがストレージにアクセスしようとすると、ストレージが正しく初期化されないことです。取り組んでいる依存関係の流れを示すためのチャートを作成しました。
connectと呼ばれます)。ただし、ストレージは明示的に作成されるのではなく、独自のモジュールの副作用にすぎないため、コンポーネントは作成される前にストレージを使用します。コンポーネントまたはヘルパー関数が最初に保存される時間を制御することはできません。これは非常に混乱しています。
ストレージモジュールは次のとおりですscripts/store/index.js
(☓bad)上記のように、
ストレージは副作用として作成され、エクスポートされます。ヘルパー機能も保存する必要があります。import { createStore } from 'redux' import reducers from '../reducers' const store = createStore(reducers) export default store export { getItemList } from './connect'
scripts/store/connect.js
(☓bad)これはまさに私のコンポーネントが互いに繰り返される瞬間です。ヘルパー関数は、ストレージを実行する必要があり、アプリケーションの他の部分にアクセスできるように、ストレージ初期化ファイルから同時にエクスポートされます。これがどれほど乱雑に聞こえるのかわかりますか?
import store from './' export function getItemList () { return store.getState().items.all }
solution
繰り返しますが、これは、Reactが実際にストレージにアクセスできるようになる方法と非常に似ています(ソースコードを参照)。彼らが一緒にうまく機能する理由はありますが、その概念を学んでみませんか?
アプリケーションエントリポイントは、最初にストレージを作成し、次にすべてのコンポーネントに渡します。コンポーネントは、ストレージおよびスケジュール操作に接続したり、変更をサブスクライブしたり、特定のデータを取得したりできます。 変更を見てみましょう:
scripts/store/configureStore.js
(✓Good)<モジュールを保持しましたが、代わりに、コードベースの他の場所にストレージを作成するConfigureStoreという関数をエクスポートしました。 これは単なる基本的な概念であることに注意してください。
<code>actions/ ├── game.js ├── score.js └── ... components/ ├── router.js ├── pageControls.js ├── canvas.js └── ... constants/ ├── game.js ├── score.js └── ... reducers/ ├── game.js ├── score.js └── ... store/ ├── configureStore.js ├── connect.js └── index.js utils/ ├── serviceWorker.js ├── localStorage.js ├── dom.js └── ... index.js worker.js</code>
scripts/store/connect.js(✓Good)<
接続ヘルパー関数は基本的に変更されていませんが、ストレージをパラメーターとして渡す必要があります。最初は、このソリューションを使用することをためらいました。今、私はそれらがすべてを読みやすくするのに十分であり、十分に進んでいると思います。scripts/index.js
<code>layouts/ └── default.html partials/ ├── back-button.html └── meta.html pages/ ├── about.html ├── settings.html └── ... index.html</code>
コンポーネント
2つのコンポーネントを使用することにしました:
import { createStore } from 'redux' import reducers from '../reducers' const store = createStore(reducers) export default store export { getItemList } from './connect'
および
コンテナコンポーネントしかし、私には例外があります。コンポーネントは非常に小さく、1つだけのことを行うことがあります。上記のパターンの1つに分割したくないので、混ぜることにしました。コンポーネントが成長し、より多くのロジックを取得した場合は、分離します。 スクリプト/コンポーネント/pagecontrols.js
上記の例はコンポーネントの1つです。要素のリスト(この場合、データアクション属性を持つすべての要素)があり、属性コンテンツに基づいてクリックするとアクションをスケジュールします。それだけです。その後、他のモジュールはストレージの変更を聞き、それに応じて自分自身を更新する場合があります。前述のように、コンポーネントにもDOMアップデートがある場合は、分離します。さあ、これら2つのコンポーネントタイプの明確な分離を示しましょう。
更新dom
import store from './' export function getItemList () { return store.getState().items.all }
プロジェクトを始めたときに私が抱えていたより大きな問題は、実際にDOMを更新する方法でした。 Reactは、仮想DOMと呼ばれるDOMの高速インメモリ表現を使用して、DOMの更新を最小限に抑えます。
私は実際に同じことをすることを考えています。私のアプリケーションが大きくなり、domがより退屈である場合、仮想domに切り替えるかもしれませんが、今のところclassicdom操作をしています。 Reduxでうまく機能します。
基本的なプロセスは次のとおりです
注:私はJavaScriptのDOMに関連するものの$シンボルプレフィックスのファンです。ご想像のとおり、jqueryの$から取られています。したがって、純粋なプレゼンテーションコンポーネントファイル名には、ドル記号が付いています。
scripts/index.js
<code>actions/ ├── game.js ├── score.js └── ... components/ ├── router.js ├── pageControls.js ├── canvas.js └── ... constants/ ├── game.js ├── score.js └── ... reducers/ ├── game.js ├── score.js └── ... store/ ├── configureStore.js ├── connect.js └── index.js utils/ ├── serviceWorker.js ├── localStorage.js ├── dom.js └── ... index.js worker.js</code>
スクリプト/コンポーネント/scoreobserver/index.js
<code>layouts/ └── default.html partials/ ├── back-button.html └── meta.html pages/ ├── about.html ├── settings.html └── ... index.html</code>
updatescoreboardメソッドは他の場所で使用されます。とにかくビューが非アクティブであるため、変更が発生するたびにリストを更新することは意味がありません。また、ビューが変更されるたびに異なるコンポーネントを更新または非アクティブ化するルーティングコンポーネントもあります。そのAPIはほぼ次のとおりです
import { createStore } from 'redux' import reducers from '../reducers' const store = createStore(reducers) export default store export { getItemList } from './connect'
スクリプト/コンポーネント/scoreobserver/$ board.js
繰り返しますが、これは基本的な例であり、基本的なコンポーネントです。更新ボード()メソッドは配列を取り、それを反復し、スコアリストにコンテンツを挿入します。
import store from './' export function getItemList () { return store.getState().items.all }
スクリプト/コンポーネント/scoreobserver/$ label.js
このコンポーネントは、上記のスコアボードとほぼ同じですが、単一の要素のみを更新します。
import { createStore } from 'redux' import reducers from '../reducers' export default function configureStore () { return createStore(reducers) }
ストレージを実装することです。アプリケーションに不可欠なコンテンツを保存することだけが重要だと思います。最初は、現在のアクティブビュー、ゲーム設定、スコア、ホバーエフェクト、ユーザーの呼吸モードなど、すべてを保存しそうになりました。
これは1つのアプリケーションに関連している可能性がありますが、別のアプリケーションとは何の関係もありません。現在のビューを保存し、リロード時にまったく同じ場所で続行するのはいいことかもしれませんが、私の場合、それは有用ではなく、ユーザーエクスペリエンスが悪いと感じていました。メニューやモーダルスイッチを保存したくありませんよね?なぜユーザーはその特定の状態に戻る必要があるのですか?大規模なWebアプリケーションでは、これは理にかなっているかもしれません。しかし、私の小さなモバイルゲームフォーカスゲームでは、そこから離れたからといって設定画面に戻ります。これはかなり迷惑です。
私は反応の有無にかかわらずReduxプロジェクトを行ったことがありますが、私の主なポイントは、アプリケーション設計の大きな違いは必要ないということです。 Reactで使用される方法のほとんどは、実際に他のビュー処理設定に適合できます。これを実現するのにしばらく時間がかかりました。最初は何か違うことをしなければならないと思ったので、それが必要ではないことに気づきました。 しかし、違うのは、モジュールの初期化、それらの保存方法、およびコンポーネントがアプリケーションの全体をよく理解していることです。概念は同じままですが、実装とコードのボリュームはニーズに最適です。
Reduxは、アプリケーションをより思慮深い方法で構築するのに役立つ優れたツールです。ビューギャラリーなしで単独で使用することは、最初は非常に注意が必要ですが、最初の混乱を克服すると、何も止めることはできません。 私の方法についてどう思いますか? reduxとさまざまなビューを使用して、設定だけを処理していますか?私はあなたから聞いて、コメントでそれについて話し合いたいです。
Reduxの詳細については、「Design Issuesを解決するためにReduxの書き換えとテスト」ミニコースをご覧ください。このコースでは、WebSocket接続を通じてトピックごとに整理されたツイートを受信するReduxアプリケーションを構築します。何が起こるかについてのアイデアを提供するには、以下の無料コースをご覧ください。
プレーヤーのロード…FAQは、反応のないredux(FAQ)にあります Reduxを使用することとReactを使用しないこととReactを使用しないことの主な違いは何ですか?
Reduxの非同期操作は、通常、Redux ThunkやRedux Sagaなどのミドルウェアを使用して処理されます。これらのミドルウェアを使用すると、通常のオブジェクトではなく、機能(サンク)またはより複雑な非同期操作(SAGAS)をスケジュールできます。反応がなくても、これらのミドルウェアをReduxストレージで使用できます。 ReduxのApplyMiddleware機能を使用してストレージを作成するときは、ミドルウェアを適用するだけです。
はい、Redux DevtoolsはReactに依存せず、Reduxを使用する任意のUI層で使用できます。 Redux DevToolsをアプリケーションに統合して、Reduxストレージを作成するときにミドルウェアとして追加できます。これにより、Reactがなくても、アプリケーションのステータスとアクションをリアルタイムで確認できます。
反応とその接続関数なしでは、Reduxストレージを手動でサブスクライブし、状態が変更されたときにUIコンポーネントを更新する必要があります。 store.subscribeメソッドを使用してストアを購読できます。これは、操作がスケジュールされるたびに呼び出されるリスナー関数を取得します。このリスナー関数では、store.getStateを使用してストレージの現在の状態を取得し、それに応じてUIコンポーネントを更新できます。
はい、ReduxはReactに依存せず、任意のUI層で使用できます。 VueやAngularなどの他のライブラリやフレームワークの場合、Reactの接続関数と同様の機能を提供するバインディングが提供されます。これらのバインディングにより、UIコンポーネントを簡単にReduxストレージに接続し、状態が変更されたときにコンポーネントの更新を処理できます。
反応なしのreduxコードのテストは、Reactでテストすることに似ています。 JestやMochaなどのJavaScriptテストフレームワークを使用して、アクションクリエイターとリデューサーのユニットテストを作成できます。非同期操作をテストするには、モックストレージを使用してReduxストレージをシミュレートできます。
Reduxの副作用は、通常、Redux ThunkやRedux Sagaなどのミドルウェアを使用して処理されます。これらのミドルウェアを使用すると、副作用やAPI呼び出しなどの複雑な非同期操作を備えた機能をスケジュールできます。反応がなくても、これらのミドルウェアをReduxストレージで使用できます。
はい、reduxは純粋なJavaScriptで使用できます。 Reduxストアを作成し、アクションをスケジュールし、純粋なJavaScriptのみを使用して州の変更を購読できます。ただし、UIの更新を処理するためのReactのようなライブラリやフレームワークがない場合は、状態が変更されたときにUIコンポーネントを手動で更新する必要があります。
Reduxコードの構造は、Reactを使用するかどうかに依存しません。操作、還元剤、セレクターの分離、異なるファイルまたはフォルダーに分離したり、正規化されたモジュール式の方法で状態を整理するなど、同じベストプラクティスをReduxコードを構築するための同じベストプラクティスに従うことができます。
はい、Redux MiddlewareはReactに依存せず、Reduxを使用する任意のUIレイヤーで使用できます。 Reduxのミドルウェアは、副作用や非同期操作などを処理するために使用されます。 ReduxのApplyMiddleware機能を使用して、ReduxのApply MiddlewareをReduxストレージに使用できます。
以上が反応せずにreduxの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。