React js изменяет состояние дочернего компонента от родительского компонента

101

У меня есть два компонента: Родительский компонент, из которого я хочу изменить состояние дочернего компонента:

class ParentComponent extends Component {
  toggleChildMenu() {
    ?????????
  }
  render() {
    return (
      <div>
        <button onClick={toggleChildMenu.bind(this)}>
          Toggle Menu from Parent
        </button>
        <ChildComponent />
      </div>
    );
  }
}

И дочерний компонент :

class ChildComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false;
    }
  }

  toggleMenu() {
    this.setState({
      open: !this.state.open
    });
  }

  render() {
    return (
      <Drawer open={this.state.open}/>
    );
  }
}

Мне нужно либо изменить открытое состояние дочернего компонента из родительского компонента, либо вызвать toggleMenu () дочернего компонента из родительского компонента при нажатии кнопки в родительском компоненте?

Torayeff
источник
Возможно, вы можете сохранить дочернюю ссылку в родительском элементе и явно изменить состояние дочернего элемента, См. Этот документ
Чаоджун Чжун

Ответы:

125

Состояние должно управляться в родительском компоненте. Вы можете передать openзначение дочернему компоненту, добавив свойство.

class ParentComponent extends Component {
   constructor(props) {
      super(props);
      this.state = {
        open: false
      };

      this.toggleChildMenu = this.toggleChildMenu.bind(this);
   }

   toggleChildMenu() {
      this.setState(state => ({
        open: !state.open
      }));
   }

   render() {
      return (
         <div>
           <button onClick={this.toggleChildMenu}>
              Toggle Menu from Parent
           </button>
           <ChildComponent open={this.state.open} />
         </div>
       );
    }
}

class ChildComponent extends Component {
    render() {
      return (
         <Drawer open={this.props.open}/>
      );
    }
}
Оливье Буассе
источник
Можно ли это использовать для управления свойством css, например display? например, если моя опора «open» содержит либо «none», либо «inline-block», будет ли обновляться опора отображения css?
deusofnull
3
Да, это, по сути, то, что делает пакет response-classnames, но он также позволяет вам всегда применять набор имен классов и условно применять другие. Примерно так: classNames({ foo: true, bar: this.props.open });// => 'foo', когда this.props.open = false и 'foo bar', когда this.props.open = true.
deusofnull
1
Как мы можем изменить открытое состояние дочернего компонента?
Priyabrata Atha 02
1
вы можете добавить свойство toggleв ChildComponent <ChildComponent open={this.state.open} toggle={this.toggleChildMenu.bind(this)} />и вызвать this.props.toggle()дочерний компонент
Olivier Boissé
1
Я не понимаю, вы можете вызывать его где угодно в дочернем компоненте, как только вы указали это свойство при объявлении ChildComponent-><ChildComponent toggle={this.toggleChildMenu.bind(this)} />
Olivier Boissé
25

Родительский компонент может управлять дочерним состоянием, передавая опору дочернему элементу, а потомок конвертирует эту опору в состояние с помощью componentWillReceiveProps.

class ParentComponent extends Component {
  state = { drawerOpen: false }
  toggleChildMenu = () => {
    this.setState({ drawerOpen: !this.state.drawerOpen })
  }
  render() {
    return (
      <div>
        <button onClick={this.toggleChildMenu}>Toggle Menu from Parent</button>
        <ChildComponent drawerOpen={this.state.drawerOpen} />
      </div>
    )
  }
}

class ChildComponent extends Component {
  constructor(props) {
    super(props)
    this.state = {
      open: false
    }
  }

  componentWillReceiveProps(props) {
    this.setState({ open: props.drawerOpen })
  }

  toggleMenu() {
    this.setState({
      open: !this.state.open
    })
  }

  render() {
    return <Drawer open={this.state.open} />
  }
}
Мигель Савиньяно
источник
1
в React 16 используйте getDerivedStateFromProps
Fadi Abo Msalam
1
@FadiAboMsalam Я использую реакцию версии 16.7.0 с версией @ Types / react версии 16.7.18. По крайней мере, со стороны TypeScript, похоже, нет getDerivedStateFromProps(). Тем не менее, ответ Мигеля, предлагающий использовать componentWillReceiveProps(props), доступен и работал как шарм в моем окружении.
Манфред
Как в этом случае изменение состояния toggleMenu () внутри дочернего компонента достигнет родительского? Представьте, что я закрываю ящик, как родительский компонент узнает, что он закрыт?
norman123123
20

Приведенный выше ответ частично верен для меня, но в моем сценарии я хочу установить значение в состояние, потому что я использовал значение для отображения / переключения модального окна. Поэтому я использовал как показано ниже. Надеюсь, это кому-то поможет.

class Child extends React.Component {
  state = {
    visible:false
  };

  handleCancel = (e) => {
      e.preventDefault();
      this.setState({ visible: false });
  };

  componentDidMount() {
    this.props.onRef(this)
  }

  componentWillUnmount() {
    this.props.onRef(undefined)
  }

  method() {
    this.setState({ visible: true });
  }

  render() {
    return (<Modal title="My title?" visible={this.state.visible} onCancel={this.handleCancel}>
      {"Content"}
    </Modal>)
  }
}

class Parent extends React.Component {
  onClick = () => {
    this.child.method() // do stuff
  }
  render() {
    return (
      <div>
        <Child onRef={ref => (this.child = ref)} />
        <button onClick={this.onClick}>Child.method()</button>
      </div>
    );
  }
}

Ссылка - https://github.com/kriasoft/react-starter-kit/issues/909#issuecomment-252969542

Джейсон
источник
2
Это то, что я хочу, но мне интересно, почему бы просто не использовать React refs? см. документ
Chaojun Zhong
Что делает опора onRef?
norman123123
2

Вы можете использовать createRef для изменения состояния дочернего компонента от родительского компонента. Вот все шаги.

  1. Создайте метод для изменения состояния в дочернем компоненте.

    2 - Создайте ссылку на дочерний компонент в родительском компоненте с помощью React.createRef ().

    3 - Присоедините ссылку к дочернему компоненту, используя ref = {}.

    4 - Вызовите метод дочернего компонента, используя this.yor-reference.current.method.

Родительский компонент


class ParentComponent extends Component {
constructor()
{
this.changeChild=React.createRef()
}
  render() {
    return (
      <div>
        <button onClick={this.changeChild.current.toggleMenu()}>
          Toggle Menu from Parent
        </button>
        <ChildComponent ref={this.changeChild} />
      </div>
    );
  }
}

Дочерний компонент


class ChildComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false;
    }
  }

  toggleMenu=() => {
    this.setState({
      open: !this.state.open
    });
  }

  render() {
    return (
      <Drawer open={this.state.open}/>
    );
  }
}



Праная Кумар
источник
1

Вы можете отправить опору от родителя и использовать ее в дочернем компоненте, чтобы вы основывали изменения состояния дочернего элемента на отправленных изменениях опоры, и вы можете справиться с этим, используя getDerivedStateFromProps в дочернем компоненте.

Джуба Фурали
источник