Reactの紹介、パート3

公開: 2020-07-30

先週、Reactコンポーネントは、アプリケーションの状態(の一部)をグラフィカルに表現したものにすぎないことを確認しました。 実装した例では、コンポーネントは、カウンターの値と、その値を増減できる2つのボタンを示しました。 トリックは単純でした。コンポーネントのpropsはデータ関数の両方にすることができます。

これまでのところ、このチュートリアルのパート1とパート2から学んだ2つの主なアイデアは次のとおりです。

  • Reactコンポーネントは、一連のプロパティを受け取り、それをレンダリングするために必要なHTMLを生成する純粋関数です。
  • Reactコンポーネントが受け取るプロパティは、(a)UIに表示する必要のあるデータ、および(b)DOMイベントへのコールバックとして接続されると、アプリの状態を変更する関数です。

さて、この第3部では、このアーキテクチャに関する知識をもう少し広げ、 WordPressストアの使用方法を学びます。 これらを使用すると、アプリケーションの状態をクリーンでテスト可能でUIに依存しない方法で定義できます。

例を拡張する

このチュートリアルの第2部では、値を増減するための2つのボタンを備えたカウンターを作成しました。 これを行うために、 index.jsファイルに変更可能な変数とそれを変更する関数を追加しました。 カウンターコンポーネント:

 export const Counter = ( { value, onIncrease, onDecrease } ) => ( <div> <div>Counter: <strong>{ value }</strong></div> <button onClick={ onIncrease }>+</button> <button onClick={ onDecrease }>-</button> </div> );

その後、必要なすべての小道具を受け取ることができます。

 // Import dependencies import { render } from '@wordpress/element'; import { Counter } from './components/counter'; // Store value let value = 0; function setValue( newValue ) { value = newValue; } // Render component in DOM const wrapper = document.getElementById( 'react-example-wrapper' ); render( <Counter value={ value } onIncrease={ () => setValue( value + 1 ) } onDecrease={ () => setValue( value - 1 ) } />, wrapper );

さて、今日は、状態管理を適切かつ適切に実装する方法を学びます。 しかし、最初に、より複雑な例を目指しましょう。一度に複数のカウンターを持つことができるようにアプリを拡張し、WordPressストアを使用してそれらすべてを管理する方法を見てみましょう。 最終結果(次の投稿で実装します)は次のようになります。

ReactとReduxを備えた複数のカウンター
ReactコンポーネントとReduxベースのWordPressストアで実装された複数のカウンター。

アプリケーションの状態を定義する

このような問題に直面した場合、最初に考慮すべきことは、アプリの状態をどのように管理するかです。 また、関数を使用してのみ状態の読み取りと書き込みができると仮定すると、そのための最も簡単な方法は、そのAPI、つまり、クエリと更新を可能にする関数について考えることです。 私たちの場合、私は提案するかもしれません:

  • 新しいカウンターを追加する
  • カウンターxの削除
  • カウンターxの値を設定します
  • 私たちのアプリが持っているすべてのカウンターのリストを取得します
  • カウンターxの値を取得します

ただし、別のアプローチを使用したい場合があります(たとえば、特定のカウンターをインクリメントするための関数と、それをデクリメントするための別の関数を作成したい場合があります)。

このインターフェイスを定義したら、この状態を追跡するために必要な情報、特に、そのために使用するデータ構造について検討する必要があります。 この例では、いくつかのカウンターを追跡し、各カウンターxについて、その値を知りたいと考えています。 この取り組みに役立つデータ構造は何ですか?

このxが何であるかに応じて、1つのデータ構造または別のデータ構造を使用することをお勧めします。 たとえば、 xがカウンターのインデックスである場合(つまり、 1番目、 2番目、または3番目のカウンターの値を取得できるようにする場合)、数値の配列で十分な場合があります。 xを一意のカウンター識別子にしたい場合は、別のアプローチを使用することをお勧めします。 たとえば、IDと値のペアを持つ辞書を使用したい場合があります。

 const counters = { ae13a: 0, f18bb: 3, e889a: 1, 8b1d3: -5, };

またはオブジェクトの配列:

 const counters = [ { id: 'ae13a', value: 0 }, { id: 'f18bb', value: 3 }, { id: 'e889a', value: 1 }, { id: '8b1d3', value: -5 }, ];

アプリの状態を操作してアクセスするためのインターフェイス(必要に応じてセッターとゲッター)を最初に定義する場合、状態自体を実装する方法はブラックボックスです。 つまり、ストア自体はいつでも変更でき、APIを維持している限り、期待どおりに機能します。

WordPressでReduxベースのストアを作成する

WordPressのデータモジュールを使用すると、アプリケーションの状態を管理するための1つ以上のストアを定義できます。 このパッケージを使用して新しいストアを作成するには、次の引数を指定してregisterStore関数を使用する必要があります。

  1. ストアを一意に識別する名前
  2. ストアからデータを取得するためのすべてのゲッターを含むselectorsオブジェクト
  3. 更新要求をトリガーする関数を持つactionsオブジェクト(これが何を意味するかについては、この投稿の後半で説明します)
  4. 特定のアクションがトリガーされたときに状態を更新する役割を担うreducer関数

実際の例を見てみましょう。 先週の例を続けて、 srcに新しいstoreフォルダーを作成します。 次に、次のコードを使用してindex.jsファイルを作成します。

 // Load dependencies import { registerStore } from '@wordpress/data'; import reducer from './reducer'; import * as actions from './actions'; import * as selectors from './selectors'; registerStore( 'react-example/counters', { actions, reducer, selectors, } );

スニペットは非常に単純ですよね? 話していたregisterStore関数と、まだ作成していないいくつかの依存関係( reduceractionsselectors )をインポートして、新しいストアを登録するだけです。 一意であることを確認するためにストアに名前を付けた方法に注目してください。プラグインの名前( react-example )と、ストアの内容を定義する単語( counters )を組み合わせました。 簡単ピーシー!

ストアでのアクション

(原則として)すべてのストアに必要なものの1つは、その状態を変更できるようにする一連の関数です。 この例では、アクションはsrc/store/actions.jsにあります。

 export function addCounter( counterId ) { return { type: 'ADD_COUNTER', counterId, }; } export function removeCounter( counterId ) { return { type: 'REMOVE_COUNTER', counterId, }; } export function setCounterValue( counterId, value ) { return { type: 'SET_COUNTER_VALUE', counterId, value, }; }

予想どおり、ストアには状態を更新するための3つのアクションがあります。

  • addCounter :ストアに新しいカウンターを追加する関数。 取る唯一の引数は、新しいカウンターのIDです。
  • removeCounter :既存のカウンターを削除する関数。 繰り返しますが、必要な引数は、削除するカウンターのIDだけです。
  • setCounterValue :指定されたカウンターに新しい値を設定する関数。 明らかに、この関数は2つの引数を取ります。更新するカウンターのIDとその新しい値です。

さて、各アクションをよく見ると、驚くかもしれません。これらのアクションはどれも何も更新していないようです。 代わりに、オブジェクトを返します。 何が起きてる?

Redux(およびWordPressストアはReduxに基づいています)では、アクションによってストアが直接変更されることはありません。 代わりに、「更新要求」を通知するオブジェクトを生成します。 これらのリクエストは常に同じパターンに従います。これらは、リクエストを一意に識別するtype属性と、リクエストされた更新を正常に適用するために必要な数の追加プロパティを持つオブジェクトです。

では、実際に状態を更新する方法を見てみましょう…

ストアの状態を更新するためのレデューサーの実装

ストアアクションが更新リクエストのみを表す場合、そのようなリクエストがディスパッチされたときにストアの状態を実際に更新するための誰かまたは何かが必要です。 それがレデューサーの使用目的です。

レデューサーは、アプリケーションの現在の状態と、誰かがディスパッチしたアクションを取得し、要求された更新を適用することによって状態を更新する関数です

前のセクションで、ストアには3つのアクションがあることを確認しました。したがって、レデューサーはそれぞれを適用できる必要があります。

 import { omit } from 'lodash'; export default function reducer( state = {}, action ) { switch ( action.type ) { case 'ADD_COUNTER': return { ...state, [ action.counterId ]: 0, }; case 'REMOVE_COUNTER': return omit( state, action.counterId ); case 'SET_COUNTER_VALUE': return { ...state, [ action.counterId ]: action.value, }; } return state; }

ご覧のとおり、レデューサーは前state (ちなみに、デフォルトでは空のオブジェクト{} )と、状態を更新するための情報を含むディスパッチされたアクションを受け取ります。 レデューサーの本体は非常に単純です。

  • 実行する必要のある更新のタイプ( action.type )を識別するためのswitchステートメントで始まります。
    • ADD_COUNTERの場合、カウンター値が0に設定された新しいキーaction.counterIdを使用して新しいstateオブジェクトを生成します。
    • REMOVE_COUNTERの場合、キーaction.counterIdなしで新しいstateオブジェクトを生成します。
    • SET_COUNTER_VALUEの場合、action.counterIdの値がaction.counterIdに設定された新しいstateオブジェクトを生成しaction.value

ここで最も重要なことは、レデューサーが純粋関数である(そしてそうでなければならない)ことを理解することです。 これは、現在の状態に加える変更には、新しい状態の構築が含まれることを意味します。 したがって、いかなる状況でも、前の状態を変更する必要はありません。

ストア内のセレクター

ストアの状態を更新する方法がわかったので、学習する必要があるのは、ストアを照会する方法だけです。 必要なクエリ関数を使用してselectors.jsを定義するだけです。

 export function getCounterIds( state ) { return Object.keys( state ); } export function getCounterValue( state, counterId ) { return state[ counterId ]; }

以上です! かなり明白ですよね? ストアセレクターは、(少なくとも)1つの引数(ストアのstate )を取り、特定の値を返す関数です。 明らかに、ストア内から特定の値を返す必要がある場合、セレクターはより多くの引数を持つことができます。

たとえば、この場合、2つのセレクターを作成しました。

  • getCounterIdsは、カウンター識別子の配列を返します。 辞書/オブジェクトを使用してストアを実装したので、そのObject.keysを返すことに関心があります。
  • getCounterValueは、指定されたカウンターの特定の値を返します。 この関数は2つの引数(アプリの現在のstateと関心のあるカウンターのID)を取り、要求された値を返します。

私たちの店をテストする方法

ストアが正しく機能することをテストするには、 src/index.jsファイルを開いてimportします。

 // Import dependencies import { render } from '@wordpress/element'; import './store'; import { Counter } from './components/counter'; ...

次に、コードをトランスパイルし( npm run buildを使用)、ブラウザーに移動します。 開発ツールを開き、JavaScriptコンソールを使用していくつかのコマンドを入力します。

 dispatch = wp.data.dispatch( 'react-example/counters' ); select = wp.data.select( 'react-example/counters' ); dispatch.addCounter( 'a' ); dispatch.addCounter( 'b' ); dispatch.addCounter( 'c' ); dispatch.setCounterValue( 'a', 3 ); select.getCounterIds(); // Array(3) [ "a", "b", "c" ] select.getCounterValue( 'a' ); // 3

WordPressのdispatchおよびselect機能を使用すると、ストアが期待どおりに機能していることを確認できます。 そしてボーナスのヒント:FirefoxとChromeの両方にRedux DevToolsと呼ばれる拡張機能があり、Reduxストアを正しく表示できます。

FirefoxでのReduxDevTools
FirefoxおよびChrome用のReduxDevTools拡張機能を使用すると、Reduxストアの状態を簡単に確認できます。

次のステップ

真実は、今日の投稿は私が予想していたよりも少し長かったので、このストアを使用してUIを強化する方法を(まだ)見ることができません。 しかし、この説明が、WordPressストアがどのように機能し、プラグインの状態を管理するためにそれらをどのように使用できるかを理解するのに役立つことを願っています。

来週は、今日の例に進み、Reactコンポーネントをストアに接続して、(a)UIに表示されるものがストアに保存されている状態によって供給され、(b)ユーザーがUIを操作してストアを更新するようにします( UI自体と同様に)。

ただし、今日お見せしたすべての内容に慣れるために、宿題を提案させてください。データが次のように保存されるように、今日実装したストアを変更してください。

 const counters = [ { id: 'ae13a', value: 0 }, { id: 'f18bb', value: 3 }, { id: 'e889a', value: 1 }, { id: '8b1d3', value: -5 }, ];

そしてもはや私たちに辞書はありません。 それを機能させるには、セレクター、アクション、およびレデューサーを更新する必要がある場合があることに注意してください。 来週ソリューションを共有します

UnsplashのAnnieThebyによる注目の画像。