【问题标题】:Child component does not set the initial value passed from the parent: ReactJS子组件没有设置从父组件传来的初始值:ReactJS
【发布时间】:2019-12-23 09:34:33
【问题描述】:

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

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

我正在处理以下情况:

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

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

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

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

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

而且我还发现切换的方式有误。一旦您单击已选择的错误,就会发生这种情况

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

【问题讨论】:

  • 你需要从主组件index.js控制你的父子多选的状态。如果它是唯一的真相来源,那就最好了。

标签: javascript reactjs react-hooks setstate


【解决方案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

【讨论】:

  • 但是父状态仍然是红色的?如果任何子开关为绿色,它应该变成灰色。猜猜这不会包含在您的答案中。你的沙箱也和我的一样。可能是你没有保存:)
  • 对不起。缺少的是在设置子值后在index.js 中调用setParentSwitchValue。现在它应该涵盖你所有的情况了。
  • 非常感谢您的回答!假设有一个具有多个父级和子级开关的组件,我如何实现一个超级父级组件,它为我提供所有父级和子级的综合值。到目前为止,它只有一个父母和两个孩子
【解决方案2】:

解决这个问题的一种方法是从主组件控制父子开关。 查看working forked codesandbox

应用程序

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;

【讨论】:

  • 非常感谢我的人!假设有一个具有多个父级和子级开关的组件,我如何实现一个超级父级组件,它为我提供所有父级和子级的综合值。到目前为止,它只有一个父母和两个孩子。
  • @vjr 你可以让你的所有开关从相同的状态获取和设置它们的值。与现在所做的类似。
  • @vjr,知道了。我去看看
  • @vjr 好的,这是可行的,这将是另一个问题。加个沙箱,我去看看
  • @vjr,请开新帖
猜你喜欢
  • 2019-08-25
  • 1970-01-01
  • 1970-01-01
  • 2019-01-04
  • 2017-04-28
  • 2015-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多