首页 > 解决方案 > 子组件没有设置从父组件传来的初始值:ReactJS

问题描述

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

我无法设置从父级传递的初始值。

我正在处理以下情况:

1)当所有子设置都开启时,父母切换状态应为开启状态

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

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

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

如果在parent里面的componentDidMount里面加一个setState(可能里面会写API调用,这样switch的初始状态会被相应地设置,然后可以改变),子switch应该可以得到状态值对,但这里没有。

而且我还看到切换是以错误的方式发生的。一旦你点击已经选择的一个,它就会发生,理想情况下是错误的

尝试了以下方法,但似乎不起作用。为此,我为此切换开关使用 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}
      />
    );
  }
}

标签: javascriptreactjsreact-hookssetstate

解决方案


解决此问题的一种方法是从主组件控制父子开关。检查工作的分叉代码框

应用程序

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;

推荐阅读