React js cambia el estado del componente secundario del componente principal

101

Tengo dos componentes: Componente principal del cual quiero cambiar el estado del componente secundario:

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

Y componente secundario :

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}/>
    );
  }
}

¿Necesito cambiar el estado abierto del componente secundario del componente principal o llamar al toggleMenu () del componente secundario del componente principal cuando se hace clic en el botón del componente principal?

torayeff
fuente
Tal vez pueda mantener una referencia de niño en el padre y cambiar el estado del niño explícitamente. Vea este documento
Chaojun Zhong

Respuestas:

125

El estado debe administrarse en el componente principal. Puede transferir el openvalor al componente secundario agregando una propiedad.

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}/>
      );
    }
}
Olivier Boissé
fuente
¿Se puede usar para controlar una propiedad css como 'display'? como en, si mi prop 'open' contiene 'none' o 'inline-block', ¿se actualizará el prop de visualización css?
deusofnull
3
Sí, eso es esencialmente lo que hace el paquete react-classnames, pero también le permite aplicar siempre un conjunto de nombres de clases y aplicar condicionalmente otros. Así: classNames({ foo: true, bar: this.props.open });// => 'foo' cuando this.props.open = false y 'foo bar' cuando this.props.open = true.
deusofnull
1
¿Cómo podemos cambiar el estado abierto en el componente hijo?
Priyabrata Atha
1
puede agregar una propiedad toggleal ChildComponent <ChildComponent open={this.state.open} toggle={this.toggleChildMenu.bind(this)} />y llamar this.props.toggle()al componente secundario
Olivier Boissé
1
No entiendo, puede llamarlo donde quiera en el componente secundario tan pronto como haya especificado esta propiedad al declarar el ChildComponent-><ChildComponent toggle={this.toggleChildMenu.bind(this)} />
Olivier Boissé
25

El componente principal puede administrar el estado del niño pasando un accesorio al niño y el niño convierte este accesorio en estado usando 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} />
  }
}
miguel savignano
fuente
1
en react 16 use getDerivedStateFromProps
Fadi Abo Msalam
1
@FadiAboMsalam Estoy usando react versión 16.7.0 con @ Types / react versión 16.7.18. Al menos en el lado de TypeScript no parece haberlo getDerivedStateFromProps(). Sin embargo, la respuesta de Miguel que sugiere usar componentWillReceiveProps(props)está disponible y funcionó como un encanto en mi entorno.
Manfred
En este caso, ¿cómo el cambio de estado toggleMenu () dentro del componente secundario llegaría al padre? Imagina que cierro el cajón, ¿cómo sabría el componente principal que está cerrado?
norman123123
20

La respuesta anterior es parcialmente correcta para mí, pero en mi escenario, quiero establecer el valor en un estado, porque he usado el valor para mostrar / alternar un modal. Así que lo he usado como a continuación. Espero que ayude a alguien.

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>
    );
  }
}

Referencia: https://github.com/kriasoft/react-starter-kit/issues/909#issuecomment-252969542

Jaison
fuente
2
Esto es lo que quiero, pero me pregunto por qué no usar refs de reacción. ver documento
Chaojun Zhong
¿Qué hace el accesorio onRef?
norman123123
2

Puede utilizar createRef para cambiar el estado del componente secundario del componente principal. Aquí están todos los pasos.

  1. Cree un método para cambiar el estado en el componente secundario.

    2 - Cree una referencia para el componente secundario en el componente principal usando React.createRef ().

    3 - Adjunte una referencia con el componente secundario usando ref = {}.

    4 - Llame al método del componente hijo usando this.yor-reference.current.method.

Componente padre


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>
    );
  }
}

Componente hijo


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}/>
    );
  }
}



Pranay kumar
fuente
1

Puede enviar un accesorio del padre y usarlo en el componente secundario, por lo que basará los cambios de estado del niño en los cambios de accesorio enviados y puede manejar esto utilizando getDerivedStateFromProps en el componente secundario.

Juba Fourali
fuente