joy08
joy08

Reputation: 9662

Compute the parents state based on the data of the child components: ReactJS

I am trying to implement a settings page where I have a global settings and some kind of child settings(in form of a slider).

I have the following scenarios:

1)When all of the child settings is on , then parents switch state should be turned on state

2)When any of the child settings is off, then parents switch state should be switched to pending

3)When all of the child settings is off, then parents switch state should be switched to off state

4) Also On click of button, I need to get the current state of all the child components.

Have tried the following approach but it does not seem like working. For this , I am using react-multi-toggle for this toggle switch.

I am able to get the state whenever the you do toggling inside, but it is not propagating to parent

Can someone help here ?

Code Sandbox Link : https://codesandbox.io/s/react-multi-toggle-r5dpi

App.tsx

import React from "react";
import ReactDOM from "react-dom";
import ChildSwitch from "./ChildSwitch";
import ParentSwitch from "./ParentSwitch";
import "./styles.css";

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      parentVal: "",
      switch1Val: "",
      switch2Val: "",
      switch3Val: ""
    };
  }

  onGetChildSwitchValues = () => {
    console.log(this.state);
  };

  setChildSwitchValue = value => {
    this.setState({ value });
  };

  setParentSwitchValue = value => {
    this.setState({ value });
  };

  render() {
    const { parentVal, switch1Val, switch2Val, switch3Val } = this.state;
    return (
      <>
        Parent Switch :{" "}
        <ParentSwitch
          parentSwitch={parentVal}
          onSelect={this.setParentSwitchValue}
        />
        Child Switches :
        <ChildSwitch
          childSwitch={switch1Val}
          onSelect={this.setChildSwitchValue}
        />
        <ChildSwitch
          childSwitch={switch2Val}
          onSelect={this.setChildSwitchValue}
        />
        <ChildSwitch
          childSwitch={switch3Val}
          onSelect={this.setChildSwitchValue}
        />
        <button onClick={this.onGetChildSwitchValues}>Get Child Values</button>
      </>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);


Parent Switch


import MultiToggle from "react-multi-toggle";
import React from "react";
import "react-multi-toggle/style.css";

export default class ParentSwitch extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      options: [
        {
          displayName: "Disabled",
          value: "disabled",
          optionClass: "red"
        },
        {
          displayName: "Pending",
          value: "pending",
          optionClass: "grey"
        },
        {
          displayName: "Enabled",
          value: "enabled",
          optionClass: "green"
        }
      ],
      selected: "pending"
    };
  }

  render() {
    const { options, selected } = this.state;
    return (
      <MultiToggle
        options={options}
        selectedOption={selected}
        onSelectOption={() => {}}
      />
    );
  }
}


ChildSwitch


import MultiToggle from "react-multi-toggle";
import React from "react";

export default class ChildSwitch extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      options: [
        {
          displayName: "Disabled",
          value: "disabled",
          optionClass: "red"
        },
        {
          displayName: "Enabled",
          value: "enabled",
          optionClass: "green"
        }
      ],
      selected: "disabled"
    };
  }

  onSelectOption = selected =>
    this.setState({ selected }, () => {
      this.props.onSelect(this.state.selected);
    });

  render() {
    console.log(this.state.selected);
    const { options, selected } = this.state;
    return (
      <MultiToggle
        options={options}
        selectedOption={selected}
        onSelectOption={this.onSelectOption}
      />
    );
  }
}




Upvotes: 0

Views: 79

Answers (2)

niiapa
niiapa

Reputation: 88

I got you started with fixing your issue:

https://codesandbox.io/s/react-multi-toggle-5hvs1

The problems were... child information cannot propagate up to parent in React unless you have a single source of truth in your application either by using tools like Redux or just the local storage, which I don't advice.

So in that case, your child components need to be controlled ones. Parent should hold their state if they want to be aware of their children...

And from there you can do your comparisons for parent toggle all on or off or whatever.

Good luck.

Upvotes: 2

thathat
thathat

Reputation: 595

setChildSwitchValue = value => {
    this.setState({ value });
};

this adds {value: value} to the state and results in this state:

{parentVal: "", switch1Val: "", switch2Val: "", switch3Val: "", value: "enabled"}

Upvotes: 1

Related Questions