Child component does not set the initial value passed from the parent: ReactJS

vr12

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 am unable to set the initial that is being passed from the parent.

I am handling 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.

If add an setState inside componentDidMount inside parent(may be API call will be written inside of it , so that initial states of the switches will be set accordingly and then be able to change) , The child switches should be able to get the state value right , But here it does not.

And I also see that toggling is happening in the wrong way. Here it is happening once you click on the already selected one which is ideally wrong

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

Can someone help here ?

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

App

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: "disabled",
      switch1Val: "disabled",
      switch2Val: "disabled",
      switch3Val: "disabled"
    };
  }

  componentDidMount() {
    this.setState({
      switch1Val: "enabled",
      switch2Val: "disabled",
      switch3Val: "enabled"
    });
  }

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

  setChildSwitchValue = (whichSwitch, value) => {
    this.setState(
      prevState => Object.assign({}, prevState, { [whichSwitch]: value }),
      this.setParentSwitchValue
    );
  };

  setParentSwitchValue = () => {
    const { switch1Val, switch2Val, switch3Val } = this.state;
    const switchStates = [switch1Val, switch2Val, switch3Val];
    const parent = switchStates.every(this.isEnabled)
      ? "enabled"
      : switchStates.every(this.isDisabled)
      ? "disabled"
      : "pending";
    this.setState({ parentVal: parent });
  };

  isEnabled(value) {
    return value === "enabled";
  }

  isDisabled(value) {
    return value === "disabled";
  }

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

Parent

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

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"
        }
      ]
    };
  }

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

export default ParentSwitch;

Child

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: ""
    };
  }

  componentDidMount() {
    this.setState({ selected: this.props.childSwitch });
  }

  onSelectOption = selected => {
    if (selected === "disabled") {
      this.setState({ selected: "enabled" }, () =>
        this.props.onSelect(this.props.switchName, "enabled")
      );
    } else {
      this.setState({ selected: "disabled" }, () =>
        this.props.onSelect(this.props.switchName, "disabled")
      );
    }
  };

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

Morlo Mbakop

A way to solve this is to control parent and child switches from master component. Checkout the working forked codesandbox

APP

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: "disabled",
      switch1Val: "enabled",
      switch2Val: "disabled",
      switch3Val: "enabled"
    };
  }

  componentDidMount() {
    this.setParentSwitchValue();
  }

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

  setChildSwitchValue = (whichSwitch, selected) => {
    this.setState(
      prevState => ({ ...prevState, [whichSwitch]: selected }),
      this.setParentSwitchValue
    );
  };

  setParentSwitchValue = () => {
    const { switch1Val, switch2Val, switch3Val } = this.state;
    const switchStates = [switch1Val, switch2Val, switch3Val];
    let parent = "pending";

    if (switchStates.every(val => val === "enabled")) {
      parent = "enabled";
    }

    if (switchStates.every(val => val === "disabled")) {
      parent = "disabled";
    }

    this.setState(prevState => ({ ...prevState, parentVal: parent }));
  };

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

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

Parent

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

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"
        }
      ]
    };
  }

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

export default ParentSwitch;

Child

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

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"
        }
      ]
    };
  }

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

export default ParentSwitch;

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

send a value from the child component to the parent component reactjs

Reactjs getting a state value from a child (with hookReducer) to parent component

How to pass a value from child to parent component in reactjs

Use parent component to pass initial value to child without relying on state ReactJS

Prop passed to child component does not change it's value in child upon updating prop in parent

How to get the value from one component(Child Component) to another component (Parent Component) in reactjs?

How to invoke a function in child component based on Boolean value passed from Parent component?

Get current state of child component through prop passed by Parent - Reactjs

ReactJS modify parent state from child component

Clone an object passed from a parent component in a child component - React Hooks

Child Component doesn't render data passed from Parent component

Am Unable to pass the value from Child to Parent component(FUNCTIONAL COMPONENT) in ReactJS

Does state update of parent component assures remount of child component in ReactJS?

set a value to a prop of a component that is passed in as another prop of its parent component

Send props from parent to child and update them in child component (ReactJs)

ReactJS Passing data from child component, to parent, back to different child

ReactJS how to pass child component title from parent component

How to pass Array from Parent component to Child component in reactjs

How to force update child component from parent component in reactjs

How to send data from child component to parent component in reactjs

How to track state of parent component from child component in ReactJs?

Angular 2: How to set default value of field from parent component back to child component?

Reactjs getting a state value from a child component

Child component does not get state from parent

React, should a hook result be passed down from parent to child component?

Parent State not updating when passed data from child component

React: Props undefined when passed from Parent to Child Function Component

Passing the value from the child to parent component and then to the child component again

Angular Parent Component property does not get updated when changing value from Child Component