Reactアプリケーションでサービスを利用する

201
Dennis Nerush 2016-03-08 12:53.

私は、ロジックをサービス/ファクトリに抽出し、それらをコントローラで使用できる角度のある世界から来ています。

Reactアプリケーションで同じことを実現する方法を理解しようとしています。

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

このロジックはどこに書くべきですか?フラックスを使用している場合、店舗で?または、より良いオプションはありますか?

11 answers

66
aphenine 2017-07-15 08:30.

最初の答えは、現在のコンテナとプレゼンターのパラダイムを反映していません。

パスワードの検証など、何かを行う必要がある場合は、それを実行する関数がある可能性があります。その関数を小道具として再利用可能なビューに渡すことになります。

コンテナ

したがって、それを行う正しい方法は、その関数をプロパティとして持つValidatorContainerを記述し、フォームをその中にラップして、適切な小道具を子に渡すことです。ビューに関しては、バリデータコンテナがビューをラップし、ビューがコンテナロジックを消費します。

検証はすべてコンテナーのプロパティで実行できますが、サードパーティのバリデーターまたは任意の単純な検証サービスを使用している場合は、サービスをコンテナーコンポーネントのプロパティとして使用し、コンテナーのメソッドで使用できます。私はこれを安らかなコンポーネントに対して行いましたが、非常にうまく機能します。

プロバイダー

もう少し構成が必要な場合は、プロバイダー/コンシューマーモデルを使用できます。プロバイダーは、最上位のアプリケーションオブジェクト(マウントするオブジェクト)の近くとその下をラップし、プロバイダーの一部または最上位レイヤーで構成されたプロパティをコンテキストAPIに提供する高レベルのコンポーネントです。次に、コンテキストを消費するようにコンテナ要素を設定します。

親子コンテキストの関係は、互いに近くにある必要はありません。子が何らかの方法で子孫になっている必要があります。ReduxストアとReactRouterはこのように機能します。私はそれを使用して、残りのコンテナーにルートの残りのコンテキストを提供しました(独自のコンテキストを提供しない場合)。

(注:コンテキスト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でカバーできます。

新しいv4react-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)
  }
}

128
Wojtek Majerski 2018-06-22 13:30.

Angularサービスが、コンテキストに依存しない一連のメソッドを提供する単なるオブジェクトであることに気付くと、問題は非常に単純になります。それをより複雑に見せているのは、AngularDIメカニズムだけです。DIは、インスタンスの作成と保守を処理するので便利ですが、実際には必要ありません。

axiosという名前の人気のあるAJAXライブラリ(おそらく聞いたことがあるでしょう)を考えてみましょう。

import axios from "axios";
axios.post(...);

サービスとして動作しませんか?これは、特定のロジックを担当する一連のメソッドを提供し、メインコードから独立しています。

あなたの例のケースは、入力を検証するための分離されたメソッドのセットを作成することに関するものでした(たとえば、パスワードの強度をチェックする)。私にとって明らかにアンチパターンであるコンポーネント内にこれらのメソッドを配置することを提案する人もいました。検証にXHRバックエンド呼び出しの作成と処理、または複雑な計算が含まれる場合はどうなりますか?このロジックをマウスクリックハンドラーやその他のUI固有のものと組み合わせますか?ナンセンス。コンテナ/ HOCアプローチでも同じです。値に数字が含まれているかどうかをチェックするメソッドを追加するためだけにコンポーネントをラップしますか?いい加減にして。

「ValidationService.js」という名前の新しいファイルを作成し、次のように整理します。

const ValidationService = {
    firstValidationMethod: function(value) {
        //inspect the value
    },

    secondValidationMethod: function(value) {
        //inspect the value
    }
};

export default ValidationService;

次に、コンポーネントで:

import ValidationService from "./services/ValidationService.js";

...

//inside the component
yourInputChangeHandler(event) {

    if(!ValidationService.firstValidationMethod(event.target.value) {
        //show a validation warning
        return false;
    }
    //proceed
}

このサービスはどこからでもご利用いただけます。検証ルールが変更された場合は、ValidationService.jsファイルのみに焦点を当てる必要があります。

他のサービスに依存する、より複雑なサービスが必要になる場合があります。この場合、サービスファイルは静的オブジェクトではなくクラスコンストラクターを返す可能性があるため、コンポーネントで自分でオブジェクトのインスタンスを作成できます。また、アプリケーション全体で使用されているサービスオブジェクトのインスタンスが常に1つだけであることを確認するために、単純なシングルトンを実装することを検討することもできます。

40
Kildareflare 2017-11-09 12:35.

複数のコンポーネント間で共有するフォーマットロジックが必要でした。Angular開発者としても、当然サービスに傾倒していました。

別のファイルに入れてロジックを共有しました

function format(input) {
    //convert input to output
    return output;
}

module.exports = {
    format: format
};

モジュールとしてインポートしました

import formatter from '../services/formatter.service';

//then in component

    render() {

        return formatter.format(this.props.data);
    }
32
Jake Roby 2016-03-08 18:24.

Reactの目的は、論理的に結合する必要があるものをより適切に結合することであることに注意してください。複雑な「パスワードの検証」方法を設計している場合、どこで結合する必要がありますか?

ユーザーが新しいパスワードを入力する必要があるたびに、それを使用する必要があります。これは、登録画面、「パスワードを忘れた」画面、管理者の「別のユーザーのパスワードをリセット」画面などに表示されます。

ただし、いずれの場合も、常に何らかのテキスト入力フィールドに関連付けられます。だからそれはそれが結合されるべき場所です。

入力フィールドと関連する検証ロジックのみで構成される非常に小さなReactコンポーネントを作成します。パスワード入力が必要な可能性のあるすべてのフォームにそのコンポーネントを入力します。

これは基本的にロジックのサービス/ファクトリを持つのと同じ結果ですが、入力に直接結合しています。したがって、関数は永続的に結合されているため、検証入力を探す場所を関数に指示する必要はありません。

13
Juraj 2018-01-17 15:26.

私もAngular.jsエリアから来ましたが、React.jsのサービスとファクトリーはもっとシンプルです。

プレーンな関数またはクラス、コールバックスタイル、および私のようなイベントMobxを使用できます:)

// Here we have Service class > dont forget that in JS class is Function
class HttpService {
  constructor() {
    this.data = "Hello data from HttpService";
    this.getData = this.getData.bind(this);
  }

  getData() {
    return this.data;
  }
}


// Making Instance of class > it's object now
const http = new HttpService();


// Here is React Class extended By React
class ReactApp extends React.Component {
  state = {
    data: ""
  };

  componentDidMount() {
    const data = http.getData();

    this.setState({
      data: data
    });
  }

  render() {
    return <div>{this.state.data}</div>;
  }
}

ReactDOM.render(<ReactApp />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  
  <div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

</body>
</html>

ここに簡単な例があります:

12
corolla 2017-10-13 04:37.

同じ状況:複数のAngularプロジェクトを実行してReactに移行したが、DIを介してサービスを提供する簡単な方法がないことは、欠けている部分のように思われる(サービスの詳細は別として)。

コンテキストとES7デコレータを使用して、近づけることができます。

https://jaysoo.ca/2015/06/09/react-contexts-and-dependency-injection/

これらの人はそれをさらに一歩進めたようです/別の方向に:

http://blog.wolksoftware.com/dependency-injection-in-react-powered-inversifyjs

まだ穀物に逆らって働いているような気がします。主要なReactプロジェクトに着手してから、6か月後にこの回答を再検討します。

編集:6か月後、Reactの経験を積んで戻ってきました。ロジックの性質を考慮してください。

  1. UIに(のみ)関連付けられていますか?それをコンポーネントに移動します(受け入れられた回答)。
  2. それは(のみ)状態管理に結びついていますか?サンクに移動します。
  3. 両方に結びついていますか?別のファイルに移動し、セレクターを介してコンポーネントで消費し、サンクで消費します。

再利用のためにHOCに手を伸ばす人もいますが、私にとっては、上記はほとんどすべてのユースケースをカバーしています。また、アヒルを使用して状態管理をスケーリングし、懸念事項を分離して状態UI中心にすることを検討してください。

7
bob 2017-12-10 09:12.

私もAngularの出身で、Reactを試しています。現時点では、推奨される(?)方法の1つは、高次コンポーネントを使用しているようです。

高階コンポーネント(HOC)は、コンポーネントロジックを再利用するためのReactの高度な手法です。HOC自体はReactAPIの一部ではありません。それらは、Reactの構成的性質から生まれるパターンです。

あなたが持っていると言うinputtextareaと同様に同じ検証ロジックを適用します:

const Input = (props) => (
  <input type="text"
    style={props.style}
    onChange={props.onChange} />
)
const TextArea = (props) => (
  <textarea rows="3"
    style={props.style}
    onChange={props.onChange} >
  </textarea>
)

次に、ラップされたコンポーネントの検証とスタイル設定を行うHOCを記述します。

function withValidator(WrappedComponent) {
  return class extends React.Component {
    constructor(props) {
      super(props)

      this.validateAndStyle = this.validateAndStyle.bind(this)
      this.state = {
        style: {}
      }
    }

    validateAndStyle(e) {
      const value = e.target.value
      const valid = value && value.length > 3 // shared logic here
      const style = valid ? {} : { border: '2px solid red' }
      console.log(value, valid)
      this.setState({
        style: style
      })
    }

    render() {
      return <WrappedComponent
        onChange={this.validateAndStyle}
        style={this.state.style}
        {...this.props} />
    }
  }
}

これらのHOCは、同じ検証動作を共有します。

const InputWithValidator = withValidator(Input)
const TextAreaWithValidator = withValidator(TextArea)

render((
  <div>
    <InputWithValidator />
    <TextAreaWithValidator />
  </div>
), document.getElementById('root'));

簡単なデモを作成しました。

編集:別のデモでは、小道具を使用して関数の配列を渡し、次HOCのような複数の検証関数で構成されるロジックを共有できるようにします。

<InputWithValidator validators={[validator1,validator2]} />
<TextAreaWithValidator validators={[validator1,validator2]} />

Edit2:React 16.8+は、ロジックを共有するためのもう1つの優れた方法であるフックという新機能を提供します。

const Input = (props) => {
  const inputValidation = useInputValidation()

  return (
    <input type="text"
    {...inputValidation} />
  )
}

function useInputValidation() {
  const [value, setValue] = useState('')
  const [style, setStyle] = useState({})

  function handleChange(e) {
    const value = e.target.value
    setValue(value)
    const valid = value && value.length > 3 // shared logic here
    const style = valid ? {} : { border: '2px solid red' }
    console.log(value, valid)
    setStyle(style)
  }

  return {
    value,
    style,
    onChange: handleChange
  }
}

https://stackblitz.com/edit/react-shared-validation-logic-using-hook?file=index.js

4
Alireza 2018-05-12 18:51.

Angular2 +でも、サービスはAngularに限定されません。

サービスは単なるヘルパー関数のコレクションです...

そして、それらを作成してアプリケーション全体で再利用する方法はたくさんあります...

1)以下のように、jsファイルからエクスポートされるすべての分離された関数にすることができます。

export const firstFunction = () => {
   return "firstFunction";
}

export const secondFunction = () => {
   return "secondFunction";
}
//etc

2)関数のコレクションで次のようなファクトリメソッドを使用することもできます... ES6では、関数コンストラクタではなくクラスにすることができます。

class myService {

  constructor() {
    this._data = null;
  }

  setMyService(data) {
    this._data = data;
  }

  getMyService() {
    return this._data;
  }

}

この場合、新しいキーでインスタンスを作成する必要があります...

const myServiceInstance = new myService();

また、この場合、各インスタンスには独自のライフがあるため、共有する場合は注意してください。その場合は、必要なインスタンスのみをエクスポートする必要があります...

3)関数とユーティリティが共有されない場合は、Reactコンポーネントに配置することもできます。この場合は、reactコンポーネントの関数と同じです。

class Greeting extends React.Component {
  getName() {
    return "Alireza Dezfoolian";
  }

  render() {
    return <h1>Hello, {this.getName()}</h1>;
  }
}

4)物事を処理する別の方法は、Reduxを使用することです。これは一時的なストアなので、Reactアプリケーションにある場合は、使用する多くのゲッターセッター関数で役立ちます...それは大きなストアのようなものですそれはあなたの状態を追跡し、それをあなたのコンポーネント間で共有することができるので、私たちがサービスで使用するゲッターセッターのものの多くの苦痛を取り除くことができます...

DRYコードを実行し、コードを再利用可能で読みやすくするために使用する必要があるものを繰り返さないことは常に良いことですが、項目4で説明したように、ReactアプリAngularの方法に従おうとしないでください。Reduxを使用すると、サービスとあなたはアイテム1のようないくつかの再利用可能なヘルパー機能のためにそれらを使用することを制限します...

1
sibidiba 2016-09-13 19:03.

私はあなたと同じブーツを履いています。あなたが言及した場合、私は入力検証UIコンポーネントをReactコンポーネントとして実装します。

私は、検証ロジック自体の実装を結合してはならないことに同意します。したがって、私はそれを別のJSモジュールに入れます。

つまり、結合してはならないロジックの場合は、別のファイルでJSモジュール/クラスを使用し、require / importを使用してコンポーネントを「サービス」から分離します。

これにより、2つの依存性注入と単体テストを個別に行うことができます。

1
Juraj 2018-01-17 15:31.

または、クラス継承「http」をReactコンポーネントに挿入できます

小道具オブジェクトを介して。

  1. 更新:

    ReactDOM.render(<ReactApp data={app} />, document.getElementById('root'));
    
  2. 次のようにReactコンポーネントReactAppを編集するだけです。

    class ReactApp extends React.Component {
    
    state = {
    
        data: ''
    
    }
    
        render(){
    
        return (
            <div>
            {this.props.data.getData()}      
            </div>
    
        )
        }
    }
    
0
Muhammad Shahryar 2020-05-27 05:34.

私が遭遇した再利用可能なロジックで最もよく使用されるパターンは、フックを作成するか、utilsファイルを作成することです。それはあなたが何を達成したいかによります。

hooks/useForm.js

フォームデータを検証する場合と同様に、useForm.jsという名前のカスタムフックを作成してフォームデータを提供すると、次の2つの内容を含むオブジェクトが返されます。

Object: {
    value,
    error,
}

あなたが進歩するにつれて、あなたは間違いなくそれからより多くのものを返すことができます。

utils/URL.js

別の例としては、URLから情報を抽出し、関数を含むutilsファイルを作成して、必要に応じてインポートする場合があります。

 export function getURLParam(p) {
...
}

Related questions

MORE COOL STUFF

「水曜日」シーズン1の中心には大きなミステリーがあります

「水曜日」シーズン1の中心には大きなミステリーがあります

Netflixの「水曜日」は、典型的な10代のドラマ以上のものであり、実際、シーズン1にはその中心に大きなミステリーがあります.

ボディーランゲージの専門家は、州訪問中にカミラ・パーカー・ボウルズが輝くことを可能にした微妙なケイト・ミドルトンの動きを指摘しています

ボディーランゲージの専門家は、州訪問中にカミラ・パーカー・ボウルズが輝くことを可能にした微妙なケイト・ミドルトンの動きを指摘しています

ケイト・ミドルトンは、州の夕食会と州の訪問中にカミラ・パーカー・ボウルズからスポットライトを奪いたくなかった、と専門家は言う.

一部のファンがハリー・スタイルズとオリビア・ワイルドの「非常に友好的な」休憩が永続的であることを望んでいる理由

一部のファンがハリー・スタイルズとオリビア・ワイルドの「非常に友好的な」休憩が永続的であることを望んでいる理由

一部のファンが、オリビア・ワイルドが彼女とハリー・スタイルズとの間の「難しい」が「非常に友好的」な分割を恒久的にすることを望んでいる理由を見つけてください.

エリザベス女王の死後、ケイト・ミドルトンはまだ「非常に困難な時期」を過ごしている、と王室の専門家が明らかにする 

エリザベス女王の死後、ケイト・ミドルトンはまだ「非常に困難な時期」を過ごしている、と王室の専門家が明らかにする&nbsp;

エリザベス女王の死後、ケイト・ミドルトンが舞台裏で「非常に困難な時期」を過ごしていたと伝えられている理由を調べてください.

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

パンデミックは終わったかもしれないが、Covid-19 は終わっていない

パンデミックは終わったかもしれないが、Covid-19 は終わっていない

2021 年 6 月 8 日にニューヨーク市で開催された covid-19 パンデミックで亡くなった人々の命を偲び、祝うために、ネーミング ザ ロスト メモリアルズが主催するイベントと行進の最中に、グリーンウッド墓地の正門から記念碑がぶら下がっています。週末、ジョー・バイデン大統領は、covid-19 パンデミックの終息を宣言しました。これは、過去 2 年以上にわたり、公の場でそうするための長い列の中で最新のものです。

デビル・イン・オハイオの予告編は、エミリー・デシャネルもオハイオにいることを明らかにしています

デビル・イン・オハイオの予告編は、エミリー・デシャネルもオハイオにいることを明らかにしています

オハイオ州のエミリー・デシャネル みんな早く来て、ボーンズが帰ってきた!まあ、ショーボーンズではなく、彼女を演じた俳優. エミリー・デシャネルに最後に会ってからしばらく経ちました.Emily Deschanel は、長期にわたるプロシージャルな Bones の Temperance “Bones” Brennan としてよく知られています。

ドナルド・トランプはFBIのマー・ア・ラーゴ襲撃映像をリリースする予定ですか?

ドナルド・トランプはFBIのマー・ア・ラーゴ襲撃映像をリリースする予定ですか?

どうやら、ドナルド・トランプに近い人々は、今月初めにFBIによって家宅捜索された彼のMar-a-Lago財産からの映像を公開するよう彼に勧めています. 前大統領はテープを公開するかどうかを確認していませんが、息子はフォックス・ニュースにそうなるだろうと語った.

Andor は、他の Star Wars ショーから大きな距離を置きます。

Andor は、他の Star Wars ショーから大きな距離を置きます。

アンドールの一場面。数十年前、ジョージ・ルーカスがスター・ウォーズのテレビ番組を制作するのを妨げた主な理由は、お金でした。

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、子供向けのパズルの本の序文を書き、ジョージ王子、シャーロット王女、ルイ王子と一緒にテキストを読むと述べた.

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

Yak's Produce は、数十個のつぶれたメロンを野生動物のリハビリ専門家であるレスリー グリーンと彼女のルイジアナ州の救助施設で暮らす 42 匹の動物に寄付しました。

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

8 枚目のスタジオ アルバムのリリースに向けて準備を進めているデミ ロヴァートは、「スーパー グレート ガイ」と付き合っている、と情報筋は PEOPLE に確認しています。

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

イーサン プラスの誕生日のお祝いは、TLC のウェルカム トゥ プラスビルのシーズン 4 のフィナーレで、戦争中の母親のキム プラスと妻のオリビア プラスを結びつけました。

仕事の生産性を高める 8 つのシンプルなホーム オフィスのセットアップのアイデア

仕事の生産性を高める 8 つのシンプルなホーム オフィスのセットアップのアイデア

ホームオフィスのセットアップ術を極めよう!AppExert の開発者は、家族全員が一緒にいる場合でも、在宅勤務の技術を習得しています。祖父や曽祖父が共同家族で暮らしていた頃の記憶がよみがえりました。

2022 年、私たちのデジタル ライフはどこで終わり、「リアル ライフ」はどこから始まるのでしょうか?

20 年前のタイムトラベラーでさえ、日常生活におけるデジタルおよびインターネットベースのサービスの重要性に驚くことでしょう。MySpace、eBay、Napster などのプラットフォームは、高速化に焦点を合わせた世界がどのようなものになるかを示してくれました。

ニューロマーケティングの秘密科学

ニューロマーケティングの秘密科学

マーケティング担当者が人間の欲望を操作するために使用する、最先端の (気味が悪いと言う人もいます) メソッドを探ります。カートをいっぱいにして 3 桁の領収書を持って店を出る前に、ほんの数点の商品を買いに行ったことはありませんか? あなたは一人じゃない。

地理情報システムの日: GIS 開発者として学ぶべき最高の技術スタック

地理情報システムの日: GIS 開発者として学ぶべき最高の技術スタック

私たちが住んでいる世界を確実に理解するには、データが必要です。ただし、空間参照がない場合、このデータは地理的コンテキストがないと役に立たなくなる可能性があります。

Language