Reduxアーキテクチャ。 はいまたはいいえ

本書の翻訳版である本書の著者は、彼がアプリケーションの新機能に取り組んでいるHikeメッセンジャーチームの一員であると述べています。 このチームの目標は、現実に変換し、ユーザーが好む可能性のあるアイデアを探ることです。 つまり、開発者は迅速に行動する必要があり、多くの場合、ユーザーの作業をできるだけ便利で楽しいものにすることを目的として、研究しているイノベーションに変更を加える必要があります。 このライブラリは開発を高速化し、異なるプラットフォームで同じコードを使用できるため、React Nativeを使用して実験を行うことを好みます。 さらに、Reduxライブラリを使用します。







Hikeの開発者が何か新しいことに取り組んでいるとき、研究中のソリューションのアーキテクチャについて議論するとき、彼らにはいくつかの質問があります。





実際、Reduxはこれらすべての質問に対する正しい答えを見つけるのに役立ちます。 Reduxアーキテクチャは、アプリケーションの状態をReactから分離するのに役立ちます。 これにより、アプリケーションの最上位にあるグローバルリポジトリを作成し、他のすべてのコンポーネントに状態アクセスを提供できます。



責任の分離



「責任の分離」とは何ですか? ウィキペディアはそれについて次のように述べています。「コンピューターサイエンスでは、責任の分割とは、コンピュータープログラムを機能ブロックに分割するプロセスです。 より一般的な場合、責任の分割は、問題をサブタスクを解決するための相互作用するプロセスに分割することにより、問題を解決するための単一のプロセスの単純化です。



Reduxのアーキテクチャを使用すると、次の図に示すように、アプリケーションの責任を4つのブロックに分割して、アプリケーションに責任の分離の原則を実装できます。





Reduxアーキテクチャ



これらのブロックの簡単な説明を次に示します。





例としてReduxのアーキテクチャを検討してください。



異なるコンポーネントが同じデータを必要とする場合はどうなりますか?



Hikeアプリには、ユーザーの友達リストを表示する画面があります。 数量に関する情報は、この画面の上部に表示されます。





Hikeアプリの友達画面



ここには3つのReactコンポーネントがあります。





上記を説明するfriendsContainer.jsのコードはのとおりです。



 class Container extends React.Component {   constructor(props) {     super(props);     this.state = {       friends: []     };   }   componentDidMount() {     FriendsService.fetchFriends().then((data) => {       this.setState({         friends: data       });     });   }   render() {     const { friends } = this.state;     return (       <View style={styles.flex}>       <FriendsHeader count={friends.length} text='My friends' />       {friends.map((friend) => (<FriendRow {...friend} />)) }       </View>     );   } }
      
      





このようなアプリケーションページを作成する絶対に明白な方法は、友人に関するデータをコンテナコンポーネントにロードし、それらをプロパティとして子コンポーネントに渡すことです。



友人に関するこのデータは、アプリケーションで使用される他のコンポーネントで必要になる可能性があるという事実について考えてみましょう。





チャット画面をハイキング



アプリケーションにチャット画面があり、そこに友人のリストも含まれているとします。 同じデータが、友人のリストを含む画面とチャット画面で使用されていることがわかります。 同様の状況で何をすべきか? 次の2つのオプションがあります。





これらのオプションはどちらもそれほど魅力的ではありません。 次に、Reduxアーキテクチャを使用して問題を解決する方法を見てみましょう。



Reduxを使用する



ここでは、ストレージ、アクションクリエーター、レデューサー、および2つのユーザーインターフェイスコンポーネントを使用して、データを使用して作業を整理することについて説明します。



▍1。 データウェアハウス



リポジトリには、ユーザーの友人に関するアップロードされたデータが含まれます。 このデータは、必要な場合に任意のコンポーネントに送信できます。



▍2。 アクションクリエーター



この場合、アクションの作成者は、友人に関するデータの保存と更新を目的としたイベントをディスパッチするために使用されます。 friendsActions.jsのコードは次のとおりです。



 export const onFriendsFetch = (friendsData) => { return {   type: 'FRIENDS_FETCHED',   payload: friendsData }; };
      
      





▍3。 減速機



レデューサーは、スケジュールされたアクションを表すイベントが到着して友人情報を更新するのを待ちます。 friendsReducer.jsのコードは次のとおりです。



 const INITIAL_STATE = {      friends: [],   friendsFetched: false }; function(state = INITIAL_STATE, action) {   switch(action.type) {   case 'FRIENDS_FETCHED':       return {           ...state,           friends: action.payload,           friendsFetched: true       };   } }
      
      





▍4。 友達リストコンポーネント



このコンテナコンポーネントは、友達のデータを表示し、変更時にインターフェースを更新します。 さらに、データがない場合は、リポジトリからデータをダウンロードする責任があります。 friendsContainer.jsのコードは次のとおりです。



 class Container extends React.Component {   constructor(props) {     super(props);   }   componentDidMount() {     if(!this.props.friendsFetched) {       FriendsService.fetchFriends().then((data) => {         this.props.onFriendsFetch(data);       });     }   }   render() {     const { friends } = this.props;     return (       <View style={styles.flex}>       <FriendsHeader count={friends.length} text='My friends' />       {friends.map((friend) => (<FriendRow {...friend} />)) }       </View>     );   } } const mapStateToProps = (state) => ({ ...state.friendsReducer }); const mapActionToProps = (dispatch) => ({ onFriendsFetch: (data) => {   dispatch(FriendActions.onFriendsFetch(data)); } }); export default connect(mapStateToProps, mapActionToProps)(Container);
      
      





▍5。 チャットリストコンポーネント



このコンテナコンポーネントは、ストレージからのデータも使用し、その更新に応答します。



Reduxアーキテクチャの実装について



上記のアーキテクチャを稼働状態にするのに1〜2日かかる場合がありますが、プロジェクトに変更を加える必要がある場合は、非常に簡単かつ迅速に行われます。 友人に関するデータを使用するアプリケーションに新しいコンポーネントを追加する必要がある場合、データの同期を心配したり、他のコンポーネントをやり直したりする必要なく、これを行うことができます。 コンポーネントの削除についても同じことが言えます。



テスト中



Reduxを使用する場合、各アプリケーションブロックを個別にテストできます。

たとえば、ユーザーインターフェイスの各コンポーネントは、データに依存しないことが判明しているため、ユニットテストを簡単に実行できます。 ポイントは、そのようなコンポーネントを表す関数は、同じデータに対して常に同じ表現を返すということです。 これにより、アプリケーションが予測可能になり、データの視覚化中にエラーが発生する可能性が低くなります。



各コンポーネントは、さまざまなデータを使用して包括的にテストできます。 このようなテストにより、隠れた問題が明らかになり、高品質のコードを保証できます。



データの視覚化を担当するコンポーネントだけでなく、レデューサーやアクションクリエーターも独立したテストを受けることができることに注意してください。



Reduxは素晴らしいですが、このテクノロジーを使用すると、いくつかの困難に直面しました。



Reduxを使用した問題



▍余分なテンプレートコード



Reduxアーキテクチャをアプリケーションに実装するには、あらゆる種類の奇妙な概念やエンティティに遭遇しながら、多くの時間を費やす必要があります。



これらは、いわゆるスレッド(サンク)、レデューサー(レデューサー)、アクション(アクション)、ミドルウェアレイヤー(ミドルウェア)です。これらは、関数mapStateToProps



およびmapDispatchToProps



だけでなく、それ以外の多くの機能です。 これらすべてを学ぶには時間がかかります。正しく使用する方法を学ぶには、練習が必要です。 プロジェクトには多くのファイルがあり、たとえば、データの視覚化のためのコンポーネントの1つの小さな変更により、4つのファイルの修正が必要になる場合があります。



Red Reduxリポジトリはシングルトンです



Reduxでは、コンポーネントは複数のインスタンスを持つことができますが、データウェアハウスはシングルトンパターンを使用して構築されます。 ほとんどの場合、これは問題ではありませんが、特定の状況では、データストレージへのこのようなアプローチはいくつかの問題を引き起こす可能性があります。 たとえば、コンポーネントのインスタンスが2つあるとします。 これらのインスタンスのいずれかでデータが変更されると、それらの変更は別のインスタンスに影響します。 場合によっては、この動作は望ましくない可能性があり、各コンポーネントインスタンスがデータの独自のコピーを使用する必要がある場合があります。



まとめ



Reduxアーキテクチャを実装するのに時間と労力をかける価値があるかどうかという主な質問を思い出してください。 この質問に答えて、Reduxは「はい」と言います。 このアーキテクチャは、アプリケーションの開発と開発における時間と労力の節約に役立ちます。 Reduxを使用すると、プログラマがアプリケーションを頻繁に変更しやすくなり、テストが簡単になります。 もちろん、Reduxアーキテクチャはかなりの量のテンプレートコードを提供しますが、コードを作業に便利なモジュールに分割するのに役立ちます。 このような各モジュールは、他のモジュールとは独立してテストできるため、開発段階でエラーを特定するのに役立ち、高品質のプログラムを保証できます。



親愛なる読者! プロジェクトでReduxを使用していますか?






All Articles