React js change child component's state from parent component

JavascriptReactjs

Javascript Problem Overview


I have two components: Parent Component from which I want to change child component's state:

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

And Child Component:

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

I need to either change Child Component's open state from Parent Component, or call Child Component's toggleMenu() from Parent Component when Button in Parent Component is clicked?

Javascript Solutions


Solution 1 - Javascript

The state should be managed in the parent component. You can transfer the open value to the child component by adding a property.

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

Solution 2 - Javascript

The parent component can manage child state passing a prop to child and the child convert this prop in state using 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} />
  }
}

Solution 3 - Javascript

Above answer is partially correct for me, but In my scenario, I want to set the value to a state, because I have used the value to show/toggle a modal. So I have used like below. Hope it will help someone.

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

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

Solution 4 - Javascript

You can use the createRef to change the state of the child component from the parent component. Here are all the steps.

  1. Create a method to change the state in the child component.
  2. Create a reference for the child component in parent component using React.createRef().
  3. Attach reference with the child component using ref={}.
  4. Call the child component method using this.yor-reference.current.method.

Parent component


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

Child Component


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



Solution 5 - Javascript

If you are using functional components. You can achieve this by:

const ParentComponent = () => {
   const [isOpen, setIsOpen] = useState(false)

   toggleChildMenu() {
      setIsOpen(prevValue => !prevValue)
   }

   return (
     <div>
       <button onClick={toggleChildMenu}>
         Toggle Menu from Parent
       </button>
       <Child open={isOpen} />
     </div>
   );
}



const Child = ({open}) => {
  return (
    <Drawer open={open}/>
  );
}

Solution 6 - Javascript

You can send a prop from the parent and use it in child component so you will base child's state changes on the sent prop changes and you can handle this by using getDerivedStateFromProps in the child component.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontorayeffView Question on Stackoverflow
Solution 1 - JavascriptOlivier BoisséView Answer on Stackoverflow
Solution 2 - Javascriptmiguel savignanoView Answer on Stackoverflow
Solution 3 - JavascriptJaison JamesView Answer on Stackoverflow
Solution 4 - JavascriptPranay kumarView Answer on Stackoverflow
Solution 5 - JavascriptIdreesView Answer on Stackoverflow
Solution 6 - JavascriptJuba FouraliView Answer on Stackoverflow