反応アプリケーションにおける共有論理と複雑論理との関係

6281 ワード

私のフルタイムの仕事で、私はたくさんのVueを書きます.私の趣味プロジェクトのために、私はUIフレームワークの間を行き来するか(または全く全く使用しない)の間で切り替えるのが好きです.
最近、私は反応で遊んでいて、ほとんどそれで私の時間を楽しんでいます.
しかし、私は最近、一般的な問題に遭遇しました.

問題:共有複素論理

私の複雑なUIロジックで何をすべきか?
私は、私が知っている反応を使用する少数の才能のある開発者に尋ねました.それらのいくつかはカスタム・フックのその共有ロジックを書くと言いました.
私は、それが素晴らしい考えであると思いました、しかし、フックは機能的な構成要素のためだけです.これは、クラスベースのコンポーネントを使用して誰にも役立ちません.
それで、私は、すべての反応アプリとすべての反応コンポーネント(機能的でクラス構成要素)のためにこれを扱うかなり滑らかな方法を思いつきました.それはredux、Mobxなしで動作し、ライブラリが必要です.

共有複雑論理とは何か
これにより、APIコール、asyncタスク、複数のコンポーネント間で共有されるプレゼンシャルロジックなどを意味します.
ビジネスロジックは一般的にAPIのビジネス層に住んでいます.
いくつかのフロントエンドのアプリケーションは、この問題に直面することはありませんが、UIのプレゼンロジックは時々複雑になることができます.
あなたのアプリが成長するように、あなたのビジネス要件が進化し、より複雑になるには、そのロジックを保持する場所が必要です.

アクションクリエーターにロジックを置くことはできますか?
まず最初にやったのは、この論理をアクションクリエーターに置くことでした.
私はreduxアクションクリエイターがロジックを処理しないことを発見した.
私はreduxアクションの作成者にロジックの少量を追加します.私が使っているならばredux-thunk とAPI呼び出しを行う.成功したリクエストと失敗した要求に対するもう一つのリターンを返す1つのアクションがあれば、これはうまくいきました.
しかし、私のアクション・クリエータがAPI呼び出しをしなければならなくて、それから反応に基づいて、それが行動を返すことができる前に、より多くのロジックを完了しなければならないならば、ものはひどく速くなりました.
いいえ、アクションクリエイターは、単純なロジックよりも処理するのに実際には良くない.

解決策
私が発見した私の問題の解決策は、複雑な論理、API呼び出し、共有コード、およびサービスにサービスを提供することです.
次に、サービスまたはサービスの新しいインスタンスを作成し、これらのサービスへのアクセスをコンポーネントにアクセスするために、ResponseのコンテキストAPIを使用できます.


簡単な例を見てみましょう.

サービスを作成する
サービスを必要とするので、簡単なものを作りましょう.私たちはservices フォルダ内のsrc ディレクトリと我々はサービスを呼び出すことができますdata.service.js
// src/services/data.service.js

export default class DataService {
     getSomeData() {
         return new Promise((req,res)=>{
               return setTimeout(()=>{
                   return ["Foo", "Bar", "Baz"]
             }, 1000);
         })
    }
}
上記の例では、単純な非同期リクエストをソートし、文字列の配列を返します.

コンテキストの作成
我々は今すぐに作成することができますcontext フォルダ内のsrc 文脈を保持するディレクトリ.
それから私はcontext/services.context.js ファイル.
私は、これがどんな可能な円の依存性問題も防ぐためにそれ自身のファイルにこれを保つのが好きです.
あなたが本当にそこに必要なすべてのコンテキストを作成し、それをエクスポートすることです.
// src/context/context.js

import React from "react";

export default React.createContext({});


文脈を提供する
現在、我々は我々を提供する必要がありますServiceContext そのため、子コンポーネントで消費できます.
この例ではApp.js , しかし、このアプローチはモジュール化されて、他の場所で親コンポーネントに置かれることができて、そのコンポーネントの子供たちにもアクセス可能です.
import React from 'react';
import DataService from './services/data.service';
import ServiceContext from './context/services.context';

class App extends React.Component {

  render() {
    return (
        <ServiceContext.Provider
          value={{
            dataService: new DataService()
          }}
        >
          <App />
        </ServiceContext.Provider>
    );
  }
}
我々の中でApp.js 我々は、我々の輸入ですServiceContext and DataService . それから我々はServiceContext.Provider 新しい値DataService コンテキストで使用できるインスタンス.

文脈を消費する
コンテキストを消費できるように、サンプルコンポーネントを作成しましょう.
//  src/components/example.component.js

import React from 'react'
import ServiceContext from '../context/services.context';

export default class ExampleComponent extends React.Component {

  static contextType = ServiceContext;

  async componentDidMount() {
    console.log(this.context);
    let data = await this.context.dataService.getSomeData();
  }

  render() {
    return (
      <div>
        <h1>
            Welcome To My Example Component!
        </h1>
      </div>
    )
  }
}
これを消費しますcontext 閉じるこの動画はお気に入りから削除されています.
このコンポーネントで静的な設定contextType プロパティServiceContext 我々が輸入した.
そして、我々は我々を呼び出すことができますDataService 's getSomeData 以前に作成したメソッド.

結論
どこで良い場所は、反応アプリケーションで複数のコンポーネント間で共有されるより複雑なロジックを維持することですか?
reduxを使用しているとき私の最初の考えはアクションクリエイターでした.
しかし、私はすぐにReduxアクションクリエーターは複雑なタスクを完了するのに最適ではないことを発見した.あなたのビジネスと表現のロジックが進化すると、どこかこのロジックを格納する必要があります.

私は、サービスを作成し、コンテキストAPIを使用することは素晴らしい解決策であることがわかりました.
これは、RedUx、Mobx、または他のライブラリを使用することに関係なく動作します.ライブラリはこれを実行することを防ぎませんし、実装するために反応する以外のライブラリも必要ありません.
このアプローチは柔軟である.サービスコンテキストは、任意のモジュールにスコープを付けることができますまたはそれはグローバルであることができますApp.js .
また、このアプローチは疎結合している.あなたがサービスをオーバーホールするか、完全にそれを取り除く必要があるならば、それは簡単にされることができます.
コンテキストAPIは、更新時にDOMを再レンダリングする方法のためにかなりの量の状態を保持するときにパフォーマンスの欠点を持つことができますが、このアプローチは、アプリケーションが読み込まれ、再度更新されないときにサービスが一度に初期化されるため、これらの問題を持っていません.