web-dev-qa-db-ja.com

Reactで親の状態を更新する方法

私の構造は次のようになります。

Component 1  

 - |- Component 2


 - - |- Component 4


 - - -  |- Component 5  

Component 3

コンポーネント3は、コンポーネント5の状態に応じていくつかのデータを表示するはずです。小道具は不変なので、単純にコンポーネント1の状態を保存して転送することはできません。そしてもちろん、私はreduxについて読んだことがありますが、それを使いたくはありません。反応するだけで解決できることを願っています。私が間違っている?

237
wklm

子供から親へのコミュニケーションのためには、次のように親から子へ状態を設定する関数を渡すべきです

class Parent extends React.Component {
  constructor(props) {
    super(props)

    this.handler = this.handler.bind(this)
  }

  handler() {
    this.setState({
      someVar: someValue
    })
  }

  render() {
    return <Child handler = {this.handler} />
  }
}

class Child extends React.Component {
  render() {
    return <Button onClick = {this.props.handler}/ >
  }
}

このようにして子はpropsで渡された関数の呼び出しで親の状態を更新することができます。

しかし、コンポーネント5と3は関連性がないので、コンポーネントの構造を再考する必要があります。

考えられる解決策の1つは、コンポーネント1と3の両方の状態を含む上位レベルのコンポーネントでそれらをラップすることです。このコンポーネントは、小道具を介して下位レベルの状態を設定します。

462
Ivan

OnClick関数の引数を子から親コンポーネントに渡すための以下の実用的な解決策を見つけました。

メソッド()を渡したバージョン

//ChildB component
class ChildB extends React.Component {

    render() {

        var handleToUpdate  =   this.props.handleToUpdate;
        return (<div><button onClick={() => handleToUpdate('someVar')}>
            Push me
          </button>
        </div>)
    }
}

//ParentA component
class ParentA extends React.Component {

    constructor(props) {
        super(props);
        var handleToUpdate  = this.handleToUpdate.bind(this);
        var arg1 = '';
    }

    handleToUpdate(someArg){
            alert('We pass argument from Child to Parent: ' + someArg);
            this.setState({arg1:someArg});
    }

    render() {
        var handleToUpdate  =   this.handleToUpdate;

        return (<div>
                    <ChildB handleToUpdate = {handleToUpdate.bind(this)} /></div>)
    }
}

if(document.querySelector("#demo")){
    ReactDOM.render(
        <ParentA />,
        document.querySelector("#demo")
    );
}

JSFIDDLEを見てください

Arrow関数を渡したバージョン

//ChildB component
class ChildB extends React.Component {

    render() {

        var handleToUpdate  =   this.props.handleToUpdate;
        return (<div>
          <button onClick={() => handleToUpdate('someVar')}>
            Push me
          </button>
        </div>)
    }
}

//ParentA component
class ParentA extends React.Component { 
    constructor(props) {
        super(props);
    }

    handleToUpdate = (someArg) => {
            alert('We pass argument from Child to Parent: ' + someArg);
    }

    render() {
        return (<div>
            <ChildB handleToUpdate = {this.handleToUpdate} /></div>)
    }
}

if(document.querySelector("#demo")){
    ReactDOM.render(
        <ParentA />,
        document.querySelector("#demo")
    );
}

JSFIDDLEを見てください

35
Roman

私は関数を渡すことに関する答えが好きです、それはとても便利なテクニックです。

反対に、 Flux のように、pub/subを使用するか、バリアント、ディスパッチャを使用してこれを実現することもできます。その理論は非常に単純で、コンポーネント5がコンポーネント3が聞いているメッセージをディスパッチするようにします。次に、コンポーネント3はその状態を更新して再レンダリングをトリガーします。これにはステートフルなコンポーネントが必要ですが、それはあなたの見方によって、アンチパターンであるかどうかは分からないです。私は個人的に彼らに反対しており、他の何かがディスパッチをリッスンしている状態をトップダウンから変更することを望んでいます(Reduxはこれを行いますが、追加の用語を追加します)。

import { Dispatcher } from flux
import { Component } from React

const dispatcher = new Dispatcher()

// Component 3
// Some methods, such as constructor, omitted for brevity
class StatefulParent extends Component {
  state = {
    text: 'foo'
  } 

  componentDidMount() {
    dispatcher.register( dispatch => {
      if ( dispatch.type === 'change' ) {
        this.setState({ text: 'bar' })
      }
    }
  }

  render() {
    return <h1>{ this.state.text }</h1>
  }
}

// Click handler
const onClick = event => {
  dispatcher.dispatch({
    type: 'change'
  })
}

// Component 5 in your example
const StatelessChild = props => {
  return <button onClick={ onClick }>Click me</button> 
}

Fluxのディスパッチャバンドルは非常に単純です、それは単にコールバックを登録して、どんなディスパッチが起こるときでも、ディスパッチの内容を通り過ぎてそれを呼び出すだけです(上の簡潔な例ではディスパッチにpayloadはありません、単にメッセージID)。それがあなたにとってより理にかなっているなら、あなたは非常に簡単にこれを伝統的なpub/subに適応させることができます(例えば、イベントからEventEmitterを使う、または他のバージョン)。

6
Matt Styles

私は自分自身の問題のアイデアを基本的に矢印関数で変化させて子コンポーネントからparamを渡すことで得た最も支持された答えに感謝したいと思います。

 class Parent extends React.Component {
  constructor(props) {
    super(props)
    // without bind, replaced by arrow func below
  }

  handler = (val) => {
    this.setState({
      someVar: val
    })
  }

  render() {
    return <Child handler = {this.handler} />
  }
}

class Child extends React.Component {
  render() {
    return <Button onClick = {() => this.props.handler('the passing value')}/ >
  }
}

誰かに役立つことを願っています。

5
Ardhi

OnClick関数の引数を子から親コンポーネントにparamで渡すための次のような実用的な解決策が見つかりました。

親クラス:

class Parent extends React.Component {
constructor(props) {
    super(props)

    // Bind the this context to the handler function
    this.handler = this.handler.bind(this);

    // Set some state
    this.state = {
        messageShown: false
    };
}

// This method will be sent to the child component
handler(param1) {
console.log(param1);
    this.setState({
        messageShown: true
    });
}

// Render the child component and set the action property with the handler as value
render() {
    return <Child action={this.handler} />
}}

子クラス:

class Child extends React.Component {
render() {
    return (
        <div>
            {/* The button will execute the handler function set by the parent component */}
            <Button onClick={this.props.action.bind(this,param1)} />
        </div>
    )
} }
4
H. parnian

どのレベルでも、子から親へのコミュニケーションが必要になる場合は、 context を使用することをお勧めします。親コンポーネントでは、次のように子によって呼び出せるコンテキストを定義します。

あなたのケースの親コンポーネントに3

     static childContextTypes = {
            parentMethod: React.PropTypes.func.isRequired
          };

           getChildContext() {
            return {
              parentMethod: (parameter_from_child) => this.parentMethod(parameter_from_child)
            };
          }

parentMethod(parameter_from_child){
// update the state with parameter_from_child
}

今度は子コンポーネント(あなたの場合はコンポーネント5)で、このコンポーネントに親のコンテキストを使用したいことを伝えます。

 static contextTypes = {
       parentMethod: React.PropTypes.func.isRequired
     };
render(){
    return(
      <TouchableHighlight
        onPress={() =>this.context.parentMethod(new_state_value)}
         underlayColor='gray' >


            <Text> update state in parent component </Text>


      </TouchableHighlight>
)}

demoプロジェクトは repo にあります。

2

そのため、親コンポーネントを更新する場合は、

 class ParentComponent extends React.Component {
        constructor(props){
            super(props);
            this.state = {
               page:0
            }
        }

        handler(val){
            console.log(val) // 1
        }

        render(){
          return (
              <ChildComponent onChange={this.handler} />
           )
       }
   }


class ChildComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
             page:1
        };
    }

    someMethod = (page) => {
        this.setState({ page: page });
        this.props.onChange(page)
    }

    render() {
        return (
       <Button
            onClick={() => this.someMethod()} 
       > Click
        </Button>
      )
   }
}

ここで、onChangeは、そのインスタンスにバインドされた「handler」メソッドを持つ属性です。メソッドハンドラーをChildクラスコンポーネントに渡して、props引数のonChangeプロパティを介して受け取ります。

属性onChangeは、次のようにpropsオブジェクトに設定されます。

props ={
onChange : this.handler
}

子コンポーネントに渡されます

したがって、Childコンポーネントは、このprops.onChangeのようなpropsオブジェクトのnameの値にアクセスできます

レンダリングの小道具を使用して行われます。

これで、Childコンポーネントにはonclickイベントが設定されたボタン「Click」があり、props引数オブジェクトのonChngeを介して渡されたハンドラーメソッドを呼び出します。したがって、Childのthis.props.onChangeは、親クラスの出力メソッドを保持します参照とクレジット:Bits and Pieces

1
Preetham NT

私はこのページのトップの回答を何度も使用しましたが、Reactを学びながら、バインドせず、プロップ内のインライン関数を使用せずに、より良い方法を見つけました。

ここを見てください:

class Parent extends React.Component {

  constructor() {
    super();
    this.state={
      someVar: value
    }
  }

  handleChange=(someValue)=>{
    this.setState({someVar: someValue})
  }

  render() {
    return <Child handler={this.handleChange} />
  }

}

export const Child = ({handler}) => {
  return <Button onClick={handler} />
}

キーは矢印関数にあります:

handleChange=(someValue)=>{
  this.setState({someVar: someValue})
}

もっと読むことができます こちら 。これが誰かのために役立つことを願っています=)

- ParentComponentの状態を更新するために、ParentComponentとhandleInputChangeメソッドを作成できます。 ChildComponentをインポートして、親から子コンポーネントに2つの小道具を渡します。

import React, { Component } from 'react';
import ChildComponent from './ChildComponent';

class ParentComponent extends Component {
  constructor(props) {
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.state = {
      count: '',
    };
  }

  handleInputChange(e) {
    const { value, name } = e.target;
    this.setState({ [name]: value });
  }

  render() {
    const { count } = this.state;
    return (
      <ChildComponent count={count} handleInputChange={this.handleInputChange} />
    );
  }
}
  • それでは、ChildComponentファイルを作成し、ChildComponent.jsxとして保存します。子コンポーネントにはステートがないため、このコンポーネントはステートレスです。小道具の型チェックにはprop-typesライブラリを使用します。

    import React from 'react';
    import { func, number } from 'prop-types';
    
    const ChildComponent = ({ handleInputChange, count }) => (
      <input onChange={handleInputChange} value={count} name="count" />
    );
    
    ChildComponent.propTypes = {
      count: number,
      handleInputChange: func.isRequired,
    };
    
    ChildComponent.defaultProps = {
      count: 0,
    };
    
    export default ChildComponent;
    
1
Sachin Metkari

反応が一方向データフローを促進するので、親から子にデータを渡すことしかできないようですが、その「子コンポーネント」で何かが起こったときに親自身を更新させるために、通常「コールバック関数」と呼ばれるものを使います。

親で定義された関数を「小道具」として子に渡し、子からその関数を呼び出して親コンポーネントでそれをトリガーします。

-------------------------------------------------- -----------------------------

class Parent extends React.Component {
  handler = (Value_Passed_From_SubChild) => {
    console.log("Parent got triggered when a grandchild button was clicked");
    console.log("Parent->Child->SubChild");
    console.log(Value_Passed_From_SubChild);
  }
  render() {
    return <Child handler = {this.handler} />
  }
}
class Child extends React.Component {
  render() {
    return <SubChild handler = {this.props.handler}/ >
  }
}
class SubChild extends React.Component { 
  constructor(props){
   super(props);
   this.state = {
      somethingImp : [1,2,3,4]
   }
  }
  render() {
     return <button onClick = {this.props.handler(this.state.somethingImp)}>Clickme<button/>
  }
}
React.render(<Parent />,document.getElementById('app'));

 HTML
 ----
 <div id="app"></div>

この例では、直接の子に関数を渡すことによって、SubChild - > Child - > Parentからデータを渡すことができます。

0
Vishal Bisht