1. ホーム
  2. ジャバスクリプト

[解決済み】React.jsで親コンポーネントにpropsを渡す。

2022-03-26 18:01:54

質問

子機の props は、React.js で、イベントを使用して親に送信しますか?

var Child = React.createClass({
  render: function() {
    <a onClick={this.props.onClick}>Click me</a>
  }
});

var Parent = React.createClass({
  onClick: function(event) {
    // event.component.props ?why is this not available?
  },
  render: function() {
    <Child onClick={this.onClick} />
  }
});

入力の値を渡すためにコントロールされたコンポーネントを使うことができるのは知っているが、全部を渡すことができたらいいなと思う。子コンポーネントには、調べたくない情報が含まれていることがあります。

コンポーネントをイベントにバインドする方法があるのでは?

アップデート - 2015年9月1日

1年以上Reactを使ってきて、Sebastien Lorberの回答に触発されて、子コンポーネントを親の関数の引数として渡すことは、次のような結論に達しました。 ではない というのは、Reactのやり方であり、決して良いアイデアではありません。回答を差し替えました。

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

編集 : ES6 の更新された例については、最後の例を参照してください。

この回答は、単に直接の親子関係の場合に対応するものです。親と子が多くの仲介者を持つ可能性がある場合、次のことを確認してください。 回答 .

他のソリューションは、ポイントがずれている

しかし、他の回答は非常に重要なことを見逃しています。

<ブロッククオート

React.jsで、イベントを使って子のpropsを親に渡す簡単な方法はないのでしょうか?

親はすでにその子のプロップを持っています! : もし子供がプロップを持っているならば、それは親がそのプロップを子供に提供したからです! 親がすでにプロップを持っているのは明らかなのに、なぜ子が親にプロップを返さなければならないのでしょうか?

より良い実装

これ以上複雑にする必要はないのです。

var Child = React.createClass({
  render: function () {
    return <button onClick={this.props.onClick}>{this.props.text}</button>;
  },
});

親と子一人 : 子に渡す値を使って

var Parent = React.createClass({
  getInitialState: function() {
     return {childText: "Click me! (parent prop)"};
  },
  render: function () {
    return (
      <Child onClick={this.handleChildClick} text={this.state.childText}/>
    );
  },
  handleChildClick: function(event) {
     // You can access the prop you pass to the children 
     // because you already have it! 
     // Here you have it in state but it could also be
     //  in props, coming from another parent.
     alert("The Child button text is: " + this.state.childText);
     // You can also access the target of the click here 
     // if you want to do some magic stuff
     alert("The Child HTML is: " + event.target.outerHTML);
  }
});

JsFiddle

子リストを持つ親 : 親に必要なものがすべて揃っているので、子を複雑にする必要はありません。

var Parent = React.createClass({
  getInitialState: function() {
     return {childrenData: [
         {childText: "Click me 1!", childNumber: 1},
         {childText: "Click me 2!", childNumber: 2}
     ]};
  },
  render: function () {
    var children = this.state.childrenData.map(function(childData,childIndex) {
        return <Child onClick={this.handleChildClick.bind(null,childData)} text={childData.childText}/>;
    }.bind(this));
    return <div>{children}</div>;
  },

  handleChildClick: function(childData,event) {
     alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
     alert("The Child HTML is: " + event.target.outerHTML);
  }
});

JsFiddle

を使用することも可能です。 this.handleChildClick.bind(null,childIndex) を使用し、その後に this.state.childrenData[childIndex]

を使用してバインドしていることに注意してください。 null コンテキストに関連する警告が表示されるからです。 自動バインディング というシステムです。nullを使うということは、関数のコンテキストを変更したくないということです。 参照 .

他の回答でのカプセル化とカップリングについて

これは私にとっては 悪い カップリングとカプセル化という観点からのアイデアです。

var Parent = React.createClass({
  handleClick: function(childComponent) {
     // using childComponent.props
     // using childComponent.refs.button
     // or anything else using childComponent
  },
  render: function() {
    <Child onClick={this.handleClick} />
  }
});

プロップの使用 : 上で説明したように、すでに親コンポーネントにpropsがあるので、子コンポーネント全体をpropsにアクセスするために渡すのは無駄です。

参考文献の利用 : イベントにはすでにクリックターゲットがあり、ほとんどの場合、これで十分です。 さらに、子プロセスに直接refを使用することもできます。

<Child ref="theChild" .../>

そして、親の DOM ノードにアクセスするには

React.findDOMNode(this.refs.theChild)

より高度なケースで、親にある子の複数の参照にアクセスしたい場合、子はコールバックで直接すべてのdomノードを渡すことができます。

コンポーネントはインターフェイス (props) を持っており、親は子の内部動作 (内部の DOM 構造や、どの DOM ノードに Ref を宣言するかなど) について何も仮定してはいけません。親が子の参照を使用することは、2 つのコンポーネントを緊密に結合することを意味します。

この問題を説明するために、次のような引用をします。 シャドウDOM ブラウザ内部でスライダーやスクロールバー、ビデオプレーヤーなどのレンダリングに使用されます。

<ブロッククオート

ウェブ開発者が到達できる範囲に境界を作ったのです。 実装の詳細とみなされ、アクセスできないもの。 ということです。しかし、ブラウザはこの境界を自由に行き来することができます。 この境界があることで、彼らはすべてのHTML要素を構築することができました divやspanから、昔ながらのWeb技術を使って と同じように。

問題は、子の実装の詳細を親に漏らすと、親に影響を与えずに子をリファクタリングすることが非常に困難になることです。つまり、ライブラリの作者として(あるいはShadow DOMを使うブラウザのエディタとして)、これは非常に危険なことです。

もしChromeがスクロールバーを実装して、クライアントがそのスクロールバーの内側のdomノードにアクセスできるようにしていたら、クライアントがそのスクロールバーを簡単に壊す可能性があることを意味し、Chromeがスクロールバーのリファクタリング後に自動アップデートを実行すると、アプリはより簡単に壊れてしまいます......。その代わり、CSSでスクロールバーの一部をカスタマイズするような安全なものへのアクセスしか与えません。

その他の使用について

コールバックでコンポーネント全体を渡すのは危険です。 childComponent.setState(...) または childComponent.forceUpdate() また、親の内部で新しい変数を代入することで、アプリ全体の推論が難しくなります。


編集:ES6の例

現在、多くの人がES6を使用しているため、以下はES6構文用の同じ例です。

子はとてもシンプルでいい。

const Child = ({
  onClick, 
  text
}) => (
  <button onClick={onClick}>
    {text}
  </button>
)

親はクラスでもいいし(最終的にはそれ自身で状態を管理できるが、ここではpropsとして渡している)。

class Parent1 extends React.Component {
  handleChildClick(childData,event) {
     alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
     alert("The Child HTML is: " + event.target.outerHTML);
  }
  render() {
    return (
      <div>
        {this.props.childrenData.map(child => (
          <Child
            key={child.childNumber}
            text={child.childText} 
            onClick={e => this.handleChildClick(child,e)}
          />
        ))}
      </div>
    );
  }
}

しかし、状態を管理する必要がなければ、簡素化することも可能です。

const Parent2 = ({childrenData}) => (
  <div>
     {childrenData.map(child => (
       <Child
         key={child.childNumber}
         text={child.childText} 
         onClick={e => {
            alert("The Child button data is: " + child.childText + " - " + child.childNumber);
                    alert("The Child HTML is: " + e.target.outerHTML);
         }}
       />
     ))}
  </div>
)

JsFiddle


PERF警告 (ES5/ES6に適用): もし、あなたが PureComponent または shouldComponentUpdate を使用するため、上記の実装はデフォルトでは最適化されません。 onClick={e => doSomething()} レンダリングフェーズで直接バインドすると、親がレンダリングするたびに新しい関数が作成されるからです。これがアプリのパフォーマンス上のボトルネックになっている場合は、データを子に渡し、それを "stable" コールバック(親クラスで設定し、バインドして this を使用し、クラスのコンストラクタで PureComponent の最適化を行うか、あるいは、独自の shouldComponentUpdate で、props比較チェックのコールバックは無視します。

を使用することもできます。 再コンポジット ライブラリは、高次のコンポーネントを提供し、きめ細かな最適化を実現します。

// A component that is expensive to render
const ExpensiveComponent = ({ propA, propB }) => {...}

// Optimized version of same component, using shallow comparison of props
// Same effect as React's PureRenderMixin
const OptimizedComponent = pure(ExpensiveComponent)

// Even more optimized: only updates if specific prop keys have changed
const HyperOptimizedComponent = onlyUpdateForKeys(['propA', 'propB'])(ExpensiveComponent)

この場合、Childコンポーネントを使用することで最適化することができます。

const OptimizedChild = onlyUpdateForKeys(['text'])(Child)