コンポーネントを通信させる方法はいくつかあります。いくつかはあなたのユースケースに適しています。これは、知っておくと便利だと思ったもののリストです。
反応する
親子直接コミュニケーション
const Child = ({fromChildToParentCallback}) => (
<div onClick={() => fromChildToParentCallback(42)}>
Click me
</div>
);
class Parent extends React.Component {
receiveChildValue = (value) => {
console.log("Parent received value from child: " + value); // value is 42
};
render() {
return (
<Child fromChildToParentCallback={this.receiveChildValue}/>
)
}
}
ここで、子コンポーネントは親によって提供されたコールバックを値で呼び出し、親は親の子によって提供された値を取得できます。
アプリの機能/ページを構築する場合、それは(とも呼ばれるコールバック/状態を管理する単一の親を持っている方が良いでしょうcontainer
かsmart component
)、およびすべてのチャイルズはステートレスであるためには、唯一の親に事を報告します。このようにして、親の状態を、それを必要とするすべての子と簡単に「共有」できます。
環境
React Contextは、コンポーネント階層のルートに状態を保持することを許可し、非常に深くネストされたコンポーネントにこの状態を簡単に注入できるため、支柱をすべての中間コンポーネントに渡す必要がありません。
これまで、コンテキストは実験的な機能でしたが、React 16.3では新しいAPIが利用可能です。
const AppContext = React.createContext(null)
class App extends React.Component {
render() {
return (
<AppContext.Provider value={{language: "en",userId: 42}}>
<div>
...
<SomeDeeplyNestedComponent/>
...
</div>
</AppContext.Provider>
)
}
};
const SomeDeeplyNestedComponent = () => (
<AppContext.Consumer>
{({language}) => <div>App language is currently {language}</div>}
</AppContext.Consumer>
);
コンシューマーはレンダープロップ/子関数パターンを使用しています
詳細については、このブログ投稿を確認してください。
React 16.3以前は、非常によく似たAPIを提供するreact-broadcastを使用し、以前のコンテキストAPI を使用することをお勧めします。
ポータル
2つのコンポーネントを近づけて通常の親/子のように単純な機能と通信したいが、これら2つのコンポーネントがDOMで親/子関係を持たないようにしたい場合は、ポータルを使用します。それが意味する視覚的/ CSS制約(z-index、不透明度など)。
この場合、「ポータル」を使用できます。ポータルを使用するさまざまな反応ライブラリがあり、通常はモーダル、ポップアップ、ツールチップに使用されます...
以下を検討してください。
<div className="a">
a content
<Portal target="body">
<div className="b">
b content
</div>
</Portal>
</div>
内部でレンダリングされると、次のDOMを生成する可能性がありますreactAppContainer
。
<body>
<div id="reactAppContainer">
<div className="a">
a content
</div>
</div>
<div className="b">
b content
</div>
</body>
詳細はこちら
スロット
スロットをどこかに定義し、レンダーツリーの別の場所からスロットを埋めます。
import { Slot, Fill } from 'react-slot-fill';
const Toolbar = (props) =>
<div>
<Slot name="ToolbarContent" />
</div>
export default Toolbar;
export const FillToolbar = ({children}) =>
<Fill name="ToolbarContent">
{children}
</Fill>
これはポータルに少し似ていますが、満たされたコンテンツは定義したスロットにレンダリングされますが、ポータルは通常、新しいdomノード(多くの場合、document.bodyの子)をレンダリングします。
反応スロット充填ライブラリを確認する
イベントバス
Reactのドキュメントに記載されているように:
親子関係のない2つのコンポーネント間の通信では、独自のグローバルイベントシステムをセットアップできます。イベントを受け取ったら、componentDidMount()でイベントをサブスクライブし、componentWillUnmount()でサブスクライブを解除し、setState()を呼び出します。
イベントバスのセットアップに使用できるものはたくさんあります。リスナーの配列を作成するだけで、イベントの発行時にすべてのリスナーがイベントを受け取ります。または、EventEmitterやPostalJsなどを使用できます。
フラックス
Fluxは基本的にイベントバスですが、イベントレシーバーはストアです。これは、状態がReactの外部で管理されることを除いて、基本的なイベントバスシステムと同様です。
元のFlux実装は、ハックな方法でイベントソーシングを行う試みのように見えます。
Reduxは、私にとって、イベントソーシングから最も近いFlux実装です。これは、時間旅行などのイベントソーシングの利点の多くにメリットをもたらします。Reactに厳密にリンクされているわけではなく、他の機能ビューライブラリでも使用できます。
EggheadのRedux ビデオチュートリアルは本当に素晴らしく、内部でどのように機能するかを説明しています(本当に簡単です)。
カーソル
カーソルはClojureScript / Omからのもので、Reactプロジェクトで広く使用されています。これらは、Reactの外部で状態を管理することを許可し、複数のコンポーネントがコンポーネントツリーについて何も知る必要なく、状態の同じ部分への読み取り/書き込みアクセスを許可します。
ImmutableJS、React-cursors、Omniscientなど、多くの実装が存在します
Edit 2016:小さいアプリではカーソルが正常に機能することに人々は同意しているようですが、複雑なアプリではうまくスケーリングしません。Om Nextにはカーソルがありません(最初に概念を導入したのはOmです)。
Elmアーキテクチャ
エルム・アーキテクチャは、で使用することが提案アーキテクチャであるエルム言語。ElmがReactJSでない場合でも、ElmアーキテクチャーはReactでも実行できます。
Reduxの作者であるDan Abramovは、Reactを使用してElmアーキテクチャの実装を行いました。
ReduxとElmはどちらも非常に優れており、フロントエンドでイベントソーシングの概念を強化する傾向があり、どちらも時間旅行のデバッグ、元に戻す/やり直し、再生を可能にします...
ReduxとElmの主な違いは、Elmは状態管理についてより厳格になる傾向があることです。Elmでは、ローカルコンポーネントの状態またはマウント/アンマウントフックを使用できません。すべてのDOMの変更は、グローバルな状態の変更によってトリガーされる必要があります。エルムアーキテクチャは、処理するために許可するスケーラブルなアプローチを提案ALL Reduxのは、招待はあなたが処理することのアプローチを提案しながら、単一不変オブジェクトの内部状態をMOST単一不変オブジェクトで状態のを。
Elmの概念モデルは非常に洗練されており、アーキテクチャは大規模なアプリでも適切にスケーリングできますが、実際には、実装後に入力にフォーカスを当てる、または既存のライブラリと統合するなどの単純なタスクを達成するのが難しいか、より多くのボイラープレートが必要になる場合があります命令型インターフェース(つまり、JQueryプラグイン)。関連する問題。
また、Elmアーキテクチャには、より多くのコードボイラープレートが含まれます。書くのはそれほど冗長でも複雑でもありませんが、Elmアーキテクチャーは静的型付け言語により適していると思います。
FRP
RxJS、BaconJS、Kefirなどのライブラリを使用して、コンポーネント間の通信を処理するFRPストリームを生成できます。
あなたは例えばRx-Reactを試すことができます
これらのライブラリを使用することは、ELM言語が提供するシグナルを使用することと非常に似ていると思います。
CycleJSフレームワークはReactJSを使用せず、vdomを使用します。Elmアーキテクチャと多くの類似点を共有します(ただし、vdomフックを使用できるため、実際の使用ではより簡単です)。関数の代わりにRxJを広範囲に使用します。FRPを反応する。CycleJs Eggheadビデオは、それがどのように機能するかを理解するのに最適です。
CSP
CSP(Communicating Sequential Processes)は現在人気がありますが(主にGo / goroutinesとcore.async / ClojureScriptが原因です)、JavaScriptとJS-CSPを併用することもできます。
James Longが、Reactでどのように使用できるかを説明するビデオを作成しました。
サガ
サガとは、DDD / EventSourcing / CQRSの世界に由来するバックエンドの概念であり、「プロセスマネージャ」とも呼ばれます。これは、主に副作用(API呼び出しなど)を処理するためのredux-thunkの代わりとして、redux-sagaプロジェクトによって一般化されています。ほとんどの人は現在、それは副作用のためだけに役立つと考えていますが、実際にはコンポーネントの分離に関するものです。
サーガは最後にFluxアクションを発行するため、完全に新しい通信システムよりもFluxアーキテクチャ(またはRedux)への賛辞です。これは、widget1とwidget2があり、それらを分離したい場合、widget1からwidget2をターゲットとするアクションを起動できないという考え方です。そのため、widget1はそれ自体をターゲットとするアクションのみを起動し、サガはwidget1アクションをリッスンする「バックグラウンドプロセス」であり、widget2をターゲットとするアクションをディスパッチする場合があります。サガは2つのウィジェット間の結合ポイントですが、ウィジェットは分離されたままです。
興味があればここで私の答えを見てください
結論
これらの異なるスタイルを使用した同じ小さなアプリの例を確認したい場合は、このリポジトリのブランチを確認してください。
長期的にはどのオプションが最適かわからないが、Fluxがイベントソーシングのように見えるのが本当に好きだ。
イベントソーシングの概念がわからない場合は、この非常に教育的なブログをご覧ください。ApacheSamzaを使用してデータベースを裏返しにすることは、Fluxが優れている理由を理解するための必読です(ただし、これはFRPにも当てはまる可能性があります) )
コミュニティは、最も有望なFlux実装がReduxであることに同意していると思います。Reduxは、ホットリロードにより、非常に生産的な開発者エクスペリエンスを徐々に可能にします。印象的なライブコーディングala Bret Victorの原理に関する発明のビデオが可能です!