首页 > 解决方案 > 基于对象数组形成组件

问题描述

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

//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
      }
    ]
  }
]

当父母开关被切换时(当父母被启用时,孩子将被启用,当被禁用时孩子将被禁用;),我需要获取该父母的全部信息

另外,我需要避免切换到“部分”状态,只应启用或禁用父级。“部分”只是代表性的

为此,我为此拨动开关使用 react-multi-toggle。

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

标签: javascriptreactjssetstate

解决方案


您可以重构您的Setting component,以允许它将您的开关呈现name and value according为从 API 接收的数据。我建议您为每个 id 添加一个 id switches group,这将简化您的工作。这是分叉的工作沙箱。可以对代码进行升级以适合您的用例。关键更改在Setting Component.

设置组件完整代码

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

推荐阅读