Как обновить состояние родителя в React?



моя структура выглядит следующим образом:



Component 1  

- |- Component 2


- - |- Component 4


- - - |- Component 5

Component 3


компонент 3 должен отображать некоторые данные в зависимости от состояния компонента 5.
Поскольку реквизит неизменен, я не могу просто сохранить его состояние в компоненте 1 и переслать его, верно? И да, я читал о redux, но не хочу его использовать. Я надеюсь, что это можно решить только с реагировать. Я ошибаюсь?

780   7  

7 ответов:

для связи ребенок-родитель вы должны передать функцию установки состояния от родителя к ребенку, как это

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

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

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

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

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

таким образом, ребенок может обновить состояние родителя с помощью вызова функции, переданной с реквизитами.

но вам придется переосмыслить структуру ваших компонентов, потому что, как я понимаю, компоненты 5 и 3 не связаны.

одно из возможных решений-обернуть их в компонент более высокого уровня, который будет содержит состояние обоих компонентов 1 и 3. Этот компонент установит состояние нижнего уровня через props.

Я нашел следующее рабочее решение для передачи аргумента функции 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

версия с передачей функции стрелой

//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

мне нравится ответ относительно передачи функций вокруг, его очень удобная техника.

С другой стороны, вы также можете достичь этого с помощью pub / sub или с помощью варианта, диспетчера, как Flux делает. Теория супер проста, есть компонент 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 с отправкой, просто идентификатор сообщения). Вы могли бы адаптируйте это к традиционному пабу / sub (например, используя EventEmitter от events или какую-либо другую версию) очень легко, если это имеет для вас больше смысла.

Я нашел следующее рабочее решение для передачи аргумента функции 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>
    )
} }

когда вам нужно общаться между ребенком и родителем на любом уровне вниз, то лучше использовать контекст. В Родительском компоненте определите контекст, который может быть вызван дочерним элементом, например

в Родительском компоненте в вашем случае компонент 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>
)}

вы можете найти демо-проекта РЕПО

- мы можем создать ParentComponent и с помощью метода handleInputChange обновить состояние ParentComponent. Импортируем ChildComponent и передаем два реквизита от родительского к дочернему компоненту ie.функция handleInputChange и подсчет.

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;
    
<Footer 
  action={()=>this.setState({showChart: true})}
/>

<footer className="row">
    <button type="button" onClick={this.props.action}>Edit</button>
  {console.log(this.props)}
</footer>

Try this example to write inline setState, it avoids creating another function.

Comments

    Ничего не найдено.