问题
For a setting page for an application, I have implemented a slider that has enabled(green) or disabled(red) state. And parent's settings are calculated based on the values of its children.
//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
}
]
}
];
Now based on this value, I need to form a grouping of parent and children something like this:
Label(the value should be parent_header_name) : Parent Switch Component
Label for children(children_switch_name) : Child Switch Component
Also on change of individual children switches toggling I need to get the info of that switch something like this:
For Example, Changing parent1's child1's to disabled
[
{
parent_header_name: "parent1",
children_info: [
{
child_switch_name: "child1",
isEnabled: false
}
]
}
];
In case parent1 turned to enabled I need to get all its chidren value
[
{
parent_header_name: "parent1",
children_info: [
{
child_switch_name: "child1",
isEnabled: true
},
{
child_switch_name: "child2",
isEnabled: true
}
]
}
]
And when parents switch is toggled(when the parent is enabled, children will be enabled and when disabled children will be disabled;), I need to get the entire info of that parent
Also, I need to avoid toggling to "partial" state, the parent should only be enabled or disabled. "Partial" is only representational
For this, I am using react-multi-toggle for this toggle switch.
I have tried something like this: https://codesandbox.io/s/parent-child-switches-gxfx6
回答1:
You can refactor your Setting component to allow it to renders your switches name and value according to the data received from the API. I will suggest you add an id to each of your switches group, that will ease your work. Here is forked working sandbox. The code can be uptimzed to befit your usecase. The key changes are done in the Setting Component.
Setting Component Full code
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>
);
}
}
回答2:
I would do it something like this:
You have a top level
Settingsclass that gets the settings object, saves it as its state and maps the array, creatingParentSwitchinstances, passing the full parent setting including its children and a function that updates the state ofSettings(for example with two integer arguments - parent index and child index) as props to theParentSwitchThe
ParentSwitchthen createsChildSwitches based on its props and passes theupdateSettingsfunction it got via its props to theChildSwitchWhen a
ChildSwitchis switched, it calls the function inSettings, switching the state ofSettingswhich is passed to theParentSwitchand theChildSwitchwhere it is displayed
Is this understandable? Feel free to ask about anything that might be unclear
Edit:
Here's the working codepen. You have to layout it yourself, I have already spent more than enough time with this.
https://codesandbox.io/s/parent-child-switches-jq0bp?fontsize=14
All of my code is in Switches.js
来源:https://stackoverflow.com/questions/57608349/forming-the-components-based-on-the-array-of-objects