javascript - 基于对象数组形成组件

标签 javascript reactjs setstate

对于应用程序的设置页面,我实现了一个具有启用(绿色)或禁用(红色)状态的 slider 。父级的设置是根据其子级的值计算的。

//Getting the switches configuration inside componnetDidMount something like this

var obj = [
  {
    parent_header_name: "parent1",
    children_info: [
      {
        child_switch_name: "child1",
        isEnabled: true
      },
      {
        child_switch_name: "child2",
        isEnabled: false
      }
    ]
  },
  {
    parent_header_name: "parent2",
    children_info: [
      {
        child_switch_name: "child3",
        isEnabled: true
      }
    ]
  },
  {
    parent_header_name: "parent3",
    children_info: [
      {
        child_switch_name: "child4",
        isEnabled: false
      }
    ]
  }
];

现在根据这个值,我需要形成一个父级和子级的分组,如下所示:

Label(the value should be parent_header_name) : Parent Switch Component
Label for children(children_switch_name) : Child Switch Component

此外,在更改各个子开关切换时,我需要获取该开关的信息,如下所示:

例如,将parent1的child1更改为禁用

[
  {
    parent_header_name: "parent1",
    children_info: [
      {
        child_switch_name: "child1",
        isEnabled: false
      }
    ]
  }
];

如果parent1变为启用状态,我需要获取其所有子级值

[
  {
    parent_header_name: "parent1",
    children_info: [
      {
        child_switch_name: "child1",
        isEnabled: true
      },
      {
        child_switch_name: "child2",
        isEnabled: true
      }
    ]
  }
]

当 parent 开关切换时(当 parent 启用时, child 将被启用,当禁用的 child 将被禁用;),我需要获取该 parent 的完整信息

此外,我需要避免切换到“部分”状态,父级只能启用或禁用。 “部分”仅具有代表性

为此,我使用react-multi-toggle作为此切换开关。

我尝试过这样的事情:https://codesandbox.io/s/parent-child-switches-gxfx6

最佳答案

您可以重构您的设置组件,以允许它根据从 API 接收的数据呈现您的开关名称和值。我建议您向每个开关组添加一个 ID,这将简化您的工作。 Here is forked working sandbox 。可以对代码进行升级以适合您的用例。关键更改在设置组件中完成。

设置组件完整代码

import React, { Component, Fragment } from "react";
import isEqual from "lodash.isequal";

import ChildSwitch from "./ChildSwitch";
import ParentSwitch from "./ParentSwitch";
import { PARTIAL } from "./constant";

export default class Setting extends Component {
  state = {
    parent: {
      value:
        this.props.children.length > 1
          ? PARTIAL
          : this.props.children[0].isEnabled
    },
    children: this.props.children
  };

  componentDidMount() {
    this.setParentSwitchValue();
  }

  shouldComponentUpdate(nextProps, nextState) {
    return !isEqual(this.state, nextState);
  }

  setChildSwitchValue = (id, isEnabled) => {
    let clickedChild;
    this.setState(
      prevState => ({
        ...prevState,
        children: prevState.children.map(child => {
          if (child.id === id) {
            clickedChild = { ...child, isEnabled: isEnabled };
            return clickedChild;
          } else {
            return child;
          }
        })
      }),
      () => this.setParentSwitchValue(clickedChild)
    );
  };

  setParentSwitchValue = clickedChild => {
    const { children } = this.state;
    let parentVal = PARTIAL;

    if (children.every(({ isEnabled }) => isEnabled === true)) {
      parentVal = true;
    }
    if (children.every(({ isEnabled }) => isEnabled === false)) {
      parentVal = false;
    }

    this.setState(
      prevState => ({
        ...prevState,
        parent: {
          value: parentVal
        }
      }),
      () => {
        this.handleChange();
        if (clickedChild) {
          const changed = {
            parent: {
              name: this.props.name,
              value: parentVal
            },
            child: clickedChild
          };
          console.log("This is the changed child", changed);
        }
      }
    );
  };

  setChildrenValue = value => {
    this.setState(
      prevState => ({
        ...prevState,
        parent: {
          value
        },
        children: prevState.children.map(child => ({
          ...child,
          isEnabled: value
        }))
      }),
      this.handleChange
    );
  };

  handleChange = () => {
    const { id, onChange } = this.props;
    onChange(id, this.state);
  };

  handleParentClick = parentVal => {
    if (parentVal !== PARTIAL) {
      this.setChildrenValue(parentVal);
    }
  };

  render() {
    const { parent, children } = this.state;
    const { name } = this.props;
    return (
      <div className="boxed">
        <span>{name}</span>
        <ParentSwitch
          childrenCount={children.length}
          parentSwitch={parent.value}
          onSelect={this.handleParentClick}
        />
        {children.map(({ id, name, isEnabled }) => (
          <Fragment key={id}>
            <span>{name}</span>
            <ChildSwitch
              switchName={id}
              selected={isEnabled}
              onSelect={this.setChildSwitchValue}
            />
          </Fragment>
        ))}
      </div>
    );
  }
}

关于javascript - 基于对象数组形成组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57608349/

相关文章:

javascript - 在对象数组的 react setState 中使用扩展运算符

javascript - 我如何根据在 Angular.js 页面上单击的复选框构造 .post 查询?

javascript - 如何在React中垂直滑动文本

javascript - 异步/等待未按预期工作 : ReactJS+ Async Await

flutter - Flutter:外部小部件的setState

javascript - 如何将数组的索引传递到reactJs onClick 中?

javascript - 如何将参数放入 windows.open 中的函数中?

Javascript 连接数组中的字符串

Javascript/JQuery 设置复选框的值,同时禁用其他复选框

javascript - 如何将React js文件包含在keycloak的ftl文件中?