Reactのコンポーネント間で機能を共有する正しい方法


92

私はすべて同じことをする必要がある複数のコンポーネントを持っています。(子コンポーネントにマップし、それぞれに何かを行う単純な関数)。現時点では、各コンポーネントでこのメソッドを定義しています。しかし、私はそれを一度だけ定義したいと思います。

トップレベルのコンポーネントで定義して、小道具として渡すことができます。しかし、それは完全に正しく感じられません。これは、小道具というよりもライブラリ関数です。(私にはそう思われる)。

これを行う正しい方法は何ですか?


このリンクをチェックしてください。または、グーグルで「mixins」と「HOC」を検索してください。
Borzh

回答:


38

browserifyのようなものを使用する場合は、いくつかのユーティリティ関数をエクスポートするutil.jsなどの外部ファイルを作成できます。

var doSomething = function(num) {
 return num + 1;
}

exports.doSomething = doSomething;

次に、必要に応じてそれを要求します

var doSomething = require('./util.js').doSomething;

@AnkitSinghaniyaそれは、アプリのフロントエンド状態を管理するために何を使用していますか?
deowk 2016

1
私は反応状態を使用しています。
aks 2016

なぜ「doSomething」が定義されていないのですか?
アビジットチャクラ2017

47

最新のJavascriptES6構文を使用したUtils.js

Utils.js複数の機能などでこのようなファイルを作成します

const someCommonValues = ['common', 'values'];

export const doSomethingWithInput = (theInput) => {
   //Do something with the input
   return theInput;
};

export const justAnAlert = () => {
   alert('hello');
};

次に、util関数を使用するコンポーネントで、必要な特定の関数をインポートします。すべてをインポートする必要はありません

import {doSomethingWithInput, justAnAlert} from './path/to/utils.js/file'

そして、次のようにコンポーネント内でこれらの関数を使用します。

justAnAlert();
<p>{doSomethingWithInput('hello')}</p>

1
/fileインポート行の最後には何がありますか?
アレックス

@alexこれは単なる例です。そこutil.jsにあなたの相対パスを入れて
Fangming

14

ヘルパー関数で状態を操作する場合は、次の手順に従ってください。

  1. Helpers.jsファイルを作成します。

    export function myFunc(){ return this.state.name; //define it according to your needs }

  2. コンポーネントファイルにヘルパー関数をインポートします。

    import {myFunc} from 'path-to/Helpers.js'

  3. コンストラクターで、そのヘルパー関数をクラスに追加します

    constructor(){ this.myFunc = myFunc.bind(this) }

  4. レンダリング関数でそれを使用します:

    render(){ <div>{this.myFunc()}</div> }


10

FetchUtil.handleErrorReactコンポーネント(App)で関数()を再利用する方法の例をいくつか示します。

解決策1:CommonJSモジュール構文を使用する

module.exports = {
  handleError: function(response) {
    if (!response.ok) throw new Error(response.statusText);
    return response;
  },
};

解決策2:「createClass」の使用(React v16)

util / FetchUtil.js

const createReactClass = require('create-react-class');

const FetchUtil = createReactClass({
  statics: {
    handleError: function(response) {
      if (!response.ok) throw new Error(response.statusText);
      return response;
    },
  },
  render() {
  },
});

export default FetchUtil;

注:React v15.4(またはそれ以下)を使用している場合はcreateClass、次のようにインポートする必要があります。

import React from 'react';
const FetchUtil = React.createClass({});

ソース:https//reactjs.org/blog/2017/04/07/react-v15.5.0.html#migrating-from-reactcreateclass

コンポーネント(FetchUtilを再利用します)

components / App.jsx

import Categories from './Categories.jsx';
import FetchUtil from '../utils/FetchUtil';
import Grid from 'material-ui/Grid';
import React from 'react';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {categories: []};
  }

  componentWillMount() {
    window
      .fetch('/rest/service/v1/categories')
      .then(FetchUtil.handleError)
      .then(response => response.json())
      .then(categories => this.setState({...this.state, categories}));
  }

  render() {
    return (
      <Grid container={true} spacing={16}>
        <Grid item={true} xs={12}>
          <Categories categories={this.state.categories} />
        </Grid>
      </Grid>
    );
  }
}

export default App;

7

utilファイルの作成以外のもう1つの確実なオプションは、高次のコンポーネントを使用してwithComponentMapper()ラッパーを作成することです。このコンポーネントは、コンポーネントをパラメーターとして受け取り、componentMapper()関数が小道具として渡された状態でそれを返します。

これはReactでは良い習慣と考えられています。その方法について詳しくは、こちらをご覧ください。


withComponentパターンが似ているように見えるコンポーネントの継承をReactが思いとどまらせる理由について知りたいのですが。
ワークワイズ

@Wor継承の使用は、2つのコンポーネントを意味します
Jake

4

ユーティリティ関数のように聞こえますが、その場合は、別の静的ユーティリティモジュールに入れてみませんか?

それ以外の場合、Babelのようなトランスパイラーを使用する場合は、es7の静的メソッドを利用できます。

class MyComponent extends React.Component {
  static someMethod() { ...

または、React.createClassを使用している場合は、staticsオブジェクトを使用できます。

var MyComponent = React.createClass({
  statics: {
    customMethod: function(foo) {
      return foo === 'bar';
    }
  }

ただし、これらのオプションはお勧めしません。ユーティリティメソッドのコンポーネントを含めることは意味がありません。

また、メソッドを小道具としてすべてのコンポーネントに渡すことはできません。メソッドはコンポーネントを緊密に結合し、リファクタリングをより苦痛にします。昔ながらのユーティリティモジュールをお勧めします。

もう1つのオプションは、ミックスインを使用してクラスを拡張することですが、es6 +では実行できないため、お勧めしません(この場合、メリットはわかりません)。


ミックスインに関する情報は役に立ちます。この場合、ライフサイクルイベントで何かが自動的に発生するのではなく、条件付きで関数を使用したいと思います。そう。あなたが言うように、昔ながらのユーティリティ関数がその方法です。

1
注:React.createClassReact15.5.0以降は非推奨です。create-react-appは、create-react-class代わりにnpmモジュールの使用を提案しています。
アレックスジョンソン

OPと同じことをしたいと思っていますが、ここでは少し混乱しています。リストしたオプションはどれもお勧めしません。何をしてくださいあなたがお勧め?
kkuilla 2018

たとえばdoSomething.js、関数のファイル、または複数の同様の「ユーティリティ」関数を含むファイルを作成し、utils.jsそれらを使用する必要がある場所にインポートします
Dominic

4

以下に2つのスタイルを示しますが、コンポーネントのロジックが相互にどの程度関連しているかに応じて選択する必要があります。

スタイル1-比較的関連するコンポーネントは、このようなコールバック参照を使用して作成できます./components/App.js...

<SomeItem
    ref={(instance) => {this.childA = instance}}
/>

<SomeOtherItem
    ref={(instance) => {this.childB = instance}}
/>

そして、あなたはこのようにそれらの間で共有機能を使用することができます...

this.childA.investigateComponent(this.childB);  // call childA function with childB as arg
this.childB.makeNotesOnComponent(this.childA);  // call childB function with childA as arg

スタイル2 - Utilのタイプのコンポーネントをすることができます作成には、次のように./utils/time.js...

export const getTimeDifference = function (start, end) {
    // return difference between start and end
}

そして、これらはこのように使用できます./components/App.js...

import React from 'react';
import {getTimeDifference} from './utils/time.js';

export default class App extends React.Component {
    someFunction() {
        console.log(getTimeDifference("19:00:00", "20:00:00"));
    }
}

どちらを使用しますか?

ロジックが比較的関連している場合(同じアプリでのみ一緒に使用される場合)、コンポーネント間で状態を共有する必要があります。ただし、ロジックが遠い関係にある場合(つまり、math util、text-formatting util)、utilクラス関数を作成してインポートする必要があります。


2

これにMixinを使用するべきではありませんか?https://facebook.github.io/react/docs/reusable-components.htmlを参照してください

彼らは支持を失っていますが、https: //medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750を参照してください

役に立つかもしれません


ここでは、一般的な関数をエクスポートするよりも、mixinの方が優れたソリューションであることに同意します。
タオ黄

@TaoHuang考慮すべき点がいくつかあります。1.Mixinsは将来性がなく、最近のアプリでは使用されなくなります。2。エクスポートされた関数を使用すると、コードフレームワークに依存しなくなります。これらの関数は、他のjsプロジェクトでも簡単に使用できます。> -また、ミックスインを使用しない理由については、この記事をお読みくださいfacebook.github.io/react/blog/2016/07/13/...
deowk

ミックスインは状態にアクセスして変更する可能性がありますが、トレイトはそうではありません。OPは関数ライブラリとして処理するものが必要だと言っているため、ミックスインは適切なソリューションではありません。
holdOffHunger 2017

これを更新するには、高階関数を使用します。 facebook.github.io/react/docs/higher-order-components.html
Davet 2017

最初のリンクが
切れてい
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.