反応せずにredux

尊渡假赌尊渡假赌尊渡假赌
リリース: 2025-02-17 11:09:13
オリジナル
642 人が閲覧しました

Redux without React

この記事は、Vildan Softicによって査読されました。 SetePointのコンテンツを完璧にしてくれたSetePointのすべてのピアレビューアに感謝します!

Redux without React 私は、ゼロから始めて、すべてがどのように機能するかを理解するのが好きな開発者のようなものです。私はこれが自分自身に(不必要な)ワークロードをもたらすことを知っていますが、特定のフレームワーク、ライブラリ、またはモジュールの背後にあるメカニズムを理解し理解するのに役立ちます。

最近、私は再びこの瞬間を経験し、ReduxとPure JavaScriptを使用してWebアプリケーションの開発を開始しました。この記事では、アプリケーション構造の概要を説明し、早期(最終的に失敗した)反復を調べてから、最終的に選択したソリューションと学んだことを見たいと思います。

キーポイント

  • Reduxは、純粋なJavaScriptを使用して、Reactに依存せずにアプリケーション状態を管理し、異なるUI層での状態管理における柔軟性を実証できます。
  • reduxストレージを適切に初期化および管理することが重要です。
  • Reactの仮想DOM(ステータスの更新に基づいてUIの変更を自動的に処理する)とは異なり、Pure JavaScriptとReduxを使用する場合、DOMは手動で更新する必要があります。
  • 必要なデータのみが保存されていることを確認するために、ユースケース駆動型ストレージを実装することをお勧めします。

設定

最新のフロントエンドテクノロジーを使用して高速で強力なWebアプリケーションを構築する人気のあるReact.JSとReduxの組み合わせを聞いたことがあるかもしれません。

Reactは、ユーザーインターフェイスを構築するためにFacebookが作成したコンポーネントベースのオープンソースライブラリです。 Reactは単なるビューレイヤーですが(などの完全なフレームワークではありません)、Reduxはアプリケーションの状態を管理します。これは、予測可能な状態容器として機能します。ここでは、状態全体が単一のオブジェクトツリーに保存され、いわゆるアクションを発行することによってのみ変更できます。このトピックがまったくわからない場合は、この記事を読むことをお勧めします。 この記事の残りの部分については、Reduxの専門家である必要はありませんが、少なくともその概念を特定して理解することは役立ちます。 反応のないredux - ゼロからのアプリケーション

Reduxの利点は、できるだけ早くアプリケーションの設計を前進させ、理解することを強制することです。実際に保存すべきもの、どのデータを変更できるか、変更する必要があるか、どのコンポーネントがストレージにアクセスできるかを定義し始めます。しかし、Reduxは状態にのみ焦点を合わせているため、アプリケーションの残りの部分を構築および接続する方法について少し混乱しています。 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)に入れて、その後、残りのアプリケーションでインポートできます。私はそれを後悔し、すぐに円形の依存関係を扱いました。問題は、コンポーネントがストレージにアクセスしようとすると、ストレージが正しく初期化されないことです。取り組んでいる依存関係の流れを示すためのチャートを作成しました。

Redux without React

アプリケーションのエントリポイントは、すべてのコンポーネントの初期化され、直接またはヘルパー関数を介して内部的にストレージを使用しています(ここでは

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

今は明らかなようで、理解するのに時間がかかりました。初期化をアプリケーションエントリポイント(Scripts/index.js)に移動し、必要なすべてのコンポーネントに渡すことでこれを解決しました。

繰り返しますが、これは、Reactが実際にストレージにアクセスできるようになる方法と非常に似ています(ソースコードを参照)。彼らが一緒にうまく機能する理由はありますが、その概念を学んでみませんか?

Redux without 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>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
これがアプリケーションのエントリポイントです。ストアは作成され、すべてのコンポーネントに渡されます。 PageControlsは、特定のアクションボタンのグローバルイベントリスナーを追加し、TetrisGameは実際のゲームコンポーネントです。ここでストレージを移動する前に基本的に同じように見えますが、ストレージをすべてのモジュールに個別に渡すことはありません。前述のように、コンポーネントは私の失敗した接続法を介してストレージにアクセスできます。

コンポーネント

2つのコンポーネントを使用することにしました:
import { createStore } from 'redux'
import reducers from '../reducers'

const store = createStore(reducers)

export default store
export { getItemList } from './connect'
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
プレゼンテーションレイヤー

および

コンテナコンポーネント

。プレゼンテーションコンポーネントは、純粋なDOM処理以外は何もしません。一方、コンテナコンポーネントはアクションをスケジュールしたり、変更を購読したりできます。 Dan AbramovはReactコンポーネントの素晴らしい記事を書きましたが、この一連のメソッドは他のコンポーネントアーキテクチャにも適用できます。

しかし、私には例外があります。コンポーネントは非常に小さく、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でうまく機能します。

基本的なプロセスは次のとおりです

    コンテナコンポーネントの新しいインスタンスを初期化し、内部使用のためにストレージを渡します
  • コンポーネントのサブスクリプションストレージの変更
  • および異なるプレゼンテーションレイヤーコンポーネントを使用してDOMで更新をレンダリング

注:私は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をインポート、作成、および初期化します。それは正確に何をしますか?スコアに関連するすべてのビュー要素を更新します:ゲーム中のハイスコアリストと現在のスコア情報。

スクリプト/コンポーネント/scoreobserver/index.js

<code>layouts/
└── default.html
partials/
├── back-button.html
└── meta.html
pages/
├── about.html
├── settings.html
└── ...
index.html</code>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
これは単純なコンポーネントであることを忘れないでください。ここで何が起こっているのですか? ScoreObserverコンポーネントは、ストレージへの内部参照を保存し、後で使用するために新しいインスタンスの2つのプレゼンテーションレベルコンポーネントを作成します。 initメソッドは、ストレージの更新をサブスクライブし、ストレージが変更されるたびに$ラベルコンポーネントを更新しますが、ゲームが実際に実行されている場合のみです。

updatescoreboardメソッドは他の場所で使用されます。とにかくビューが非アクティブであるため、変更が発生するたびにリストを更新することは意味がありません。また、ビューが変更されるたびに異なるコンポーネントを更新または非アクティブ化するルーティングコンポーネントもあります。そのAPIはほぼ次のとおりです

import { createStore } from 'redux'
import reducers from '../reducers'

const store = createStore(reducers)

export default store
export { getItemList } from './connect'
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
注:$(および$$)はjQueryの参照ではなく、document.queryselectorの便利なユーティリティショートカットです。

スクリプト/コンポーネント/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つの重要なポイントは、

ユースケース駆動型

ストレージを実装することです。アプリケーションに不可欠なコンテンツを保存することだけが重要だと思います。最初は、現在のアクティブビュー、ゲーム設定、スコア、ホバーエフェクト、ユーザーの呼吸モードなど、すべてを保存しそうになりました。

これは1つのアプリケーションに関連している可能性がありますが、別のアプリケーションとは何の関係もありません。現在のビューを保存し、リロード時にまったく同じ場所で続行するのはいいことかもしれませんが、私の場合、それは有用ではなく、ユーザーエクスペリエンスが悪いと感じていました。メニューやモーダルスイッチを保存したくありませんよね?なぜユーザーはその特定の状態に戻る必要があるのですか?大規模なWebアプリケーションでは、これは理にかなっているかもしれません。しかし、私の小さなモバイルゲームフォーカスゲームでは、そこから離れたからといって設定画面に戻ります。これはかなり迷惑です。

結論

私は反応の有無にかかわらずReduxプロジェクトを行ったことがありますが、私の主なポイントは、アプリケーション設計の大きな違いは必要ないということです。 Reactで使用される方法のほとんどは、実際に他のビュー処理設定に適合できます。これを実現するのにしばらく時間がかかりました。最初は何か違うことをしなければならないと思ったので、それが必要ではないことに気づきました。 しかし、違うのは、モジュールの初期化、それらの保存方法、およびコンポーネントがアプリケーションの全体をよく理解していることです。概念は同じままですが、実装とコードのボリュームはニーズに最適です。

Reduxは、アプリケーションをより思慮深い方法で構築するのに役立つ優れたツールです。ビューギャラリーなしで単独で使用することは、最初は非常に注意が必要ですが、最初の混乱を克服すると、何も止めることはできません。 私の方法についてどう思いますか? reduxとさまざまなビューを使用して、設定だけを処理していますか?私はあなたから聞いて、コメントでそれについて話し合いたいです。

Reduxの詳細については、「Design Issuesを解決するためにReduxの書き換えとテスト」ミニコースをご覧ください。このコースでは、WebSocket接続を通じてトピックごとに整理されたツイートを受信するReduxアプリケーションを構築します。何が起こるかについてのアイデアを提供するには、以下の無料コースをご覧ください。


プレーヤーのロード…FAQは、反応のないredux(FAQ)にあります Reduxを使用することとReactを使用しないこととReactを使用しないことの主な違いは何ですか?

Reduxは、任意のUIレイヤーで使用できるJavaScriptアプリケーション用の予測可能な状態コンテナです。 ReduxとReactの使用とReactを使用しないことの主な違いは、UI層がReduxストレージとどのように相互作用するかです。 Reactで使用すると、ReduxはReactのコンポーネントベースのアーキテクチャとそのライフサイクルアプローチを活用して、状態の変更が行われたときにコンポーネントの更新を自動的に処理することができます。反応がなければ、ステータスが変更されたときにストレージを手動で購読し、UIの更新を処理する必要があります。

反応せずにreduxで非同期操作を処理する方法は?

Reduxの非同期操作は、通常、Redux ThunkやRedux Sagaなどのミドルウェアを使用して処理されます。これらのミドルウェアを使用すると、通常のオブジェクトではなく、機能(サンク)またはより複雑な非同期操作(SAGAS)をスケジュールできます。反応がなくても、これらのミドルウェアをReduxストレージで使用できます。 ReduxのApplyMiddleware機能を使用してストレージを作成するときは、ミドルウェアを適用するだけです。

反応せずにredux devtoolsを使用できますか?

はい、Redux DevtoolsはReactに依存せず、Reduxを使用する任意のUI層で使用できます。 Redux DevToolsをアプリケーションに統合して、Reduxストレージを作成するときにミドルウェアとして追加できます。これにより、Reactがなくても、アプリケーションのステータスとアクションをリアルタイムで確認できます。

ReactなしでUIコンポーネントのReduxストレージに接続する方法は?

反応とその接続関数なしでは、Reduxストレージを手動でサブスクライブし、状態が変更されたときにUIコンポーネントを更新する必要があります。 store.subscribeメソッドを使用してストアを購読できます。これは、操作がスケジュールされるたびに呼び出されるリスナー関数を取得します。このリスナー関数では、store.getStateを使用してストレージの現在の状態を取得し、それに応じてUIコンポーネントを更新できます。

他のライブラリやVueやAngularなどのフレームワークでReduxを使用できますか?

はい、ReduxはReactに依存せず、任意のUI層で使用できます。 VueやAngularなどの他のライブラリやフレームワークの場合、Reactの接続関数と同様の機能を提供するバインディングが提供されます。これらのバインディングにより、UIコンポーネントを簡単にReduxストレージに接続し、状態が変更されたときにコンポーネントの更新を処理できます。

反応せずにreduxコードをテストする方法は?

反応なしのreduxコードのテストは、Reactでテストすることに似ています。 JestやMochaなどのJavaScriptテストフレームワークを使用して、アクションクリエイターとリデューサーのユニットテストを作成できます。非同期操作をテストするには、モックストレージを使用してReduxストレージをシミュレートできます。

反応せずにreduxの副作用に対処する方法は?

Reduxの副作用は、通常、Redux ThunkやRedux Sagaなどのミドルウェアを使用して処理されます。これらのミドルウェアを使用すると、副作用やAPI呼び出しなどの複雑な非同期操作を備えた機能をスケジュールできます。反応がなくても、これらのミドルウェアをReduxストレージで使用できます。

純粋なJavaScriptでReduxを使用できますか?

はい、reduxは純粋なJavaScriptで使用できます。 Reduxストアを作成し、アクションをスケジュールし、純粋なJavaScriptのみを使用して州の変更を購読できます。ただし、UIの更新を処理するためのReactのようなライブラリやフレームワークがない場合は、状態が変更されたときにUIコンポーネントを手動で更新する必要があります。

反応せずにreduxコードを構築する方法は?

Reduxコードの構造は、Reactを使用するかどうかに依存しません。操作、還元剤、セレクターの分離、異なるファイルまたはフォルダーに分離したり、正規化されたモジュール式の方法で状態を整理するなど、同じベストプラクティスをReduxコードを構築するための同じベストプラクティスに従うことができます。

反応せずにReduxミドルウェアを使用できますか?

はい、Redux MiddlewareはReactに依存せず、Reduxを使用する任意のUIレイヤーで使用できます。 Reduxのミドルウェアは、副作用や非同期操作などを処理するために使用されます。 ReduxのApplyMiddleware機能を使用して、ReduxのApply MiddlewareをReduxストレージに使用できます。

以上が反応せずにreduxの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート