【问题标题】:Forming the components based on the array of objects基于对象数组形成组件
【发布时间】:2019-08-22 11:29:00
【问题描述】:

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

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

【问题讨论】:

  • 请澄清:您的问题到底是什么?您的示例似乎在我的浏览器中运行
  • @Taxel 我已经硬编码了开关配置,我的意思是我没有动态生成开关。现在基于上面的对象数组,我需要将父开关和子开关分组,并在单个切换时获取该开关的信息。
  • 还是一头雾水。我会考虑用更多代码以明确直接的方法重写问题。
  • @iwaduarte 会有很多代码。所以尽量避免它。如果您看到 Settings.js 渲染方法,则每个组始终有一个父级和两个子级。但是我有这个用例,我可以跨组为父级创建任意数量的子级,因此要根据上述对象数组动态渲染它,我需要帮助。希望你能得到我:)

标签: javascript reactjs setstate


【解决方案1】:

您可以重构您的 Setting component 以允许它将您的开关 name and value according 呈现为从 API 接收的数据。我建议您为每个switches group 添加一个 ID,这将简化您的工作。 Here is forked working sandbox。可以对代码进行升级以适合您的用例。关键更改在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>
    );
  }
}

【讨论】:

  • @vjr,您可以在更改父或子时获得所需的设置。处理这些事件的函数已明确命名。你的 PO 有没有提到你想在哪里找到并把这些 settings values?。至于避免挂起状态,我相信这是另一个问题,因为开关是红色/绿色并且它们的值是正确的。我相信这可能是multi-toggle-select 的错误,或者您可以重新考虑您的方法或重组/优化代码,正如我在回答中提到的那样。
  • 这只是让服务器调用发送已更改的设置的想法。就像如果改变父母需要了解哪个父母发生了变化以及它所有的孩子的价值。还有什么孩子发生了变化及其相应的价值:)
  • 我明白了 :),您可以在 Setting ComponenthandleChange 函数中进行 API 调用。 Handle Change 每次父或子开关发生变化时都会调用。
  • 如果你想让 swich 不洗牌,你不能在绑定之前对它们进行排序,或者切片并插入相同的索引。或者最好的事件可以在更改事件时减少子数组。
  • 如果只有一个孩子,我们不希望父母有部分状态。我补充说,以确保 partial 仅在至少有 2 个孩子时可用。
【解决方案2】:

我会这样做:

    1234563 Settings 的状态(例如,带有两个整数参数 - 父索引和子索引)作为 ParentSwitch 的道具
  • ParentSwitch 然后根据其 props 创建 ChildSwitches,并将通过其 props 获得的 updateSettings 函数传递给 ChildSwitch

  • 切换ChildSwitch时,调用Settings中的函数,切换Settings的状态,并传递给ParentSwitch和显示的ChildSwitch

这可以理解吗?有什么不清楚的地方可以问

编辑: 这是工作的codepen。你必须自己布局它,我已经花了足够多的时间。 https://codesandbox.io/s/parent-child-switches-jq0bp?fontsize=14 我所有的代码都在Switches.js

【讨论】:

  • 虽然我为您使用的组件使用了相同的名称,但我几乎必须重写您的所有代码。我的解释你不清楚吗?不懂的部分我可以提供代码
  • 我想我已经明白了。我刚刚开始认为我已经实现了一些部分。如果您可以编辑现有的沙箱,您的想法可能会在这里真正有所帮助:)
  • 好的,我正在做。可能需要几分钟(我正在创建所有新组件)
  • “需要获取该开关的信息”是什么意思?您只需将该功能添加到Settings 类中的onUpdateSwitch 函数即可。
  • 是的。但是,如果父母或孩子发生了变化,我将如何理解呢?如果是 child ,那么应该显示它的值。如果是父对象,则应显示整个父对象:)
猜你喜欢
  • 1970-01-01
  • 2021-04-06
  • 2018-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-11
  • 2014-05-25
  • 1970-01-01
相关资源
最近更新 更多