1. ホーム
  2. reactjs

[解決済み】Reactアプリケーションにサービスを持たせる

2022-04-15 11:42:37

質問

私は、サービス/ファクトリーにロジックを抽出し、それらを私のコントローラで消費することができたangularの世界から来ました。

Reactアプリケーションで同じことを実現するにはどうしたらいいのか、理解しようとしています。

例えば、ユーザーのパスワード入力(強度)を検証するコンポーネントがあるとします。このロジックはかなり複雑なので、コンポーネント自体にそれを書きたくはありません。

このロジックはどこに書けばいいのでしょうか?fluxを使っているならば、ストアの中に?それとも、もっといい方法があるのでしょうか?

どのように解決するのですか?

最初の回答は、現在の コンテナとプレゼンターの比較 のパラダイムがあります。

パスワードの検証のようなことをする必要がある場合、おそらくそれを行う関数を持っていることでしょう。 その関数をプロップとして再利用可能なビューに渡すことになります。

コンテナ

つまり、正しい方法は、その関数をプロパティとして持つ ValidatorContainer を書き、その中にフォームをラップして、正しいプロップを子に渡すことです。 ビューでは、バリデータコンテナがビューをラップし、ビューがコンテナのロジックを消費します。

バリデーションはすべてコンテナのプロパティで行うこともできますが、サードパーティのバリデータや簡単なバリデーションサービスを使用している場合は、そのサービスをコンテナコンポーネントのプロパティとして使用し、コンテナのメソッドで使用することができます。 私はこれをrestfulコンポーネントに対して行いましたが、非常にうまくいきました。

プロバイダー

もう少し設定が必要な場合は、Provider/Consumerモデルを使用することができます。 プロバイダとは、トップアプリケーションオブジェクト(マウントするオブジェクト)のどこか近くや下に回り込んで、自身の一部やトップレイヤーで設定したプロパティをコンテキストAPIに供給する上位コンポーネントである。 そして、コンテナ要素を設定して、コンテキストを消費させる。

コンテキストの親子関係は、近くにある必要はなく、ただ、子が何らかの形で降臨している必要がある。 ReduxのストアとReact Routerは、このような機能を備えています。 私は、(自分で提供しない場合)自分のレストコンテナのルートレストフルコンテキストを提供するために、これを使用している。

(注:コンテキストAPIはドキュメントでは実験的と記されているが、使っているものを考えると、もうそうではないと思う)。

//An example of a Provider component, takes a preconfigured restful.js
//object and makes it available anywhere in the application
export default class RestfulProvider extends React.Component {
	constructor(props){
		super(props);

		if(!("restful" in props)){
			throw Error("Restful service must be provided");
		}
	}

	getChildContext(){
		return {
			api: this.props.restful
		};
	}

	render() {
		return this.props.children;
	}
}

RestfulProvider.childContextTypes = {
	api: React.PropTypes.object
};

ミドルウェア

さらに、私は試していませんが、使われているのを見たことがあるのが、Reduxと組み合わせてミドルウェアを使用する方法です。 サービスオブジェクトをアプリケーションの外、少なくともreduxストアよりも上位に定義します。 ストアの作成時に、サービスをミドルウェアにインジェクトし、ミドルウェアはサービスに影響を与えるすべてのアクションを処理します。

このように、restful.jsオブジェクトをミドルウェアに注入し、コンテナのメソッドを独立したアクションに置き換えることができます。 フォームビューレイヤーにアクションを提供するためのコンテナコンポーネントがまだ必要ですが、connect()とmapDispatchToPropsでカバーできます。

新しいv4のreact-router-reduxは、このメソッドを使って、例えば履歴の状態に影響を与えることができます。

//Example middleware from react-router-redux
//History is our service here and actions change it.

import { CALL_HISTORY_METHOD } from './actions'

/**
 * This middleware captures CALL_HISTORY_METHOD actions to redirect to the
 * provided history object. This will prevent these actions from reaching your
 * reducer or any middleware that comes after this one.
 */
export default function routerMiddleware(history) {
  return () => next => action => {
    if (action.type !== CALL_HISTORY_METHOD) {
      return next(action)
    }

    const { payload: { method, args } } = action
    history[method](...args)
  }
}