子组件未设置从父组件传递的初始值:ReactJS

时间:2019-08-17 09:48:54

标签: javascript reactjs react-hooks setstate

我正在尝试实现一个设置页面,其中有一个全局设置和某种子设置(以滑块的形式)。

我无法设置从父级传递过来的首字母。

我正在处理以下情况:

1)当所有的孩子设置都打开时,则父母的开关状态应打开状态

2)当任何一个孩子设置关闭时,则应将父母切换状态切换为待处理状态

3)当所有的孩子设置都关闭时,则应将父母的开关状态切换到关闭状态

4)另外,在单击按钮时,我需要获取所有子组件的当前状态。

如果在parent的componentDidMount内添加setState(可能会在其中写入API调用,以便相应地设置开关的初始状态,然后可以进行更改),则子开关应该能够状态值是right,但是在这里不是。

我也看到切换是错误的。一旦您单击已经选择的错误的位置,就会发生这种情况

尝试了以下方法,但似乎不起作用。为此,我在此切换开关中使用了react-multi-toggle。

有人可以在这里帮忙吗?

代码沙箱链接:https://codesandbox.io/s/react-multi-toggle-solution-yn3fh

应用

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

父母

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;

孩子

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

2 个答案:

答案 0 :(得分:3)

解决此问题的一种方法是从主组件控制父开关和子开关。 检出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);

父母

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;

孩子

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;

答案 1 :(得分:1)

问题是childSwitch属性更改时您没有更新本地状态。因此它将保持禁用状态。为此,您必须添加componentDidUpdate方法或直接使用不带任何本地状态的属性。

在ChildSwitch中

  componentDidUpdate(prevProps) {
    if(prevProps.childSwitch !== this.props.childSwitch) {
      this.setState({ selected: this.props.childSwitch });
    }
  }

工作叉:https://codesandbox.io/s/react-multi-toggle-solution-8xnf3