场景:
我有一个场景,其中有一个孩子在“父母”中被多次呼唤。
每个子组件都有一组复选框,一个“应用”和一个清除按钮。因此,在单击“应用”时,我必须将选中的内容发送给父级。
例如,第一部分在我选中“杰克”并单击“应用”后就给了我
{key: "Jack" text: "Jack" field: "firstName" checked: true}
现在,如果我转到第2部分并选中“待处理”,我会得到
{key: "Pending" text: "Pending" field: "status" checked: true}
我不希望这种行为。相反,我希望两个值都像这样
[
{key: "Jack" text: "Jack" field: "firstName" checked: true},
{key: "Pending" text: "Pending" field: "status" checked: true}
]
或通常选中的任何一个都不会丢失以前的内容。
沙箱:https://codesandbox.io/s/stupefied-cohen-f5td1
import React from "react";
import ReactDOM from "react-dom";
import Child1 from "./Child1";
import "./styles.css";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [
{ firstName: "Jack", status: "Submitted" },
{ firstName: "Simon", status: "Pending" },
{ firstName: "Pete", status: "Approved" },
{ firstName: "Lucas", status: "Rejected" }
]
};
}
handleSetData = value => {
console.log(value); // need to get data here from all instances of child, it should not over ride
};
render() {
return (
<div>
<Child1
data={this.state.data}
param="firstName"
handleSetData={this.handleSetData}
/>
<Child1
data={this.state.data}
param="status"
handleSetData={this.handleSetData}
/>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
import React from "react";
import { Checkbox, Button } from "semantic-ui-react";
import "./styles.css";
export default class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
optionsArr: [],
originalState: []
};
}
handleItemClick = (event, data) => {
const index = this.state.data.findIndex(item => item.name === data.name);
const optionsArr = this.state.data.map((prevState, i) =>
i === index
? {
display: prevState.display,
name: prevState.name,
checked: !prevState.checked
}
: prevState
);
this.setState({ data: optionsArr });
};
componentDidMount() {
let values = this.props.data.map(arr => arr[this.props.param]);
var optionsArr = [];
for (let i = 0; i < values.length; i++) {
var options = {};
options["key"] = values[i];
options["text"] = values[i];
options["field"] = this.props.param;
options["checked"] = false;
optionsArr.push(options);
}
this.setState({ optionsArr: optionsArr, originalState: optionsArr });
}
clearSelection = event => {
this.setState({ optionsArr: this.state.originalState });
};
submitSelection = () => {
let checkedValues = this.state.optionsArr.filter(item => item.checked);
this.setState({ originalState: this.state.optionsArr }, () =>
this.props.handleSetData(checkedValues)
);
};
handleItemClick = (event, data) => {
const index = this.state.optionsArr.findIndex(
item => item.text === data.name
);
const optionsArr = this.state.optionsArr.map((prevState, i) =>
i === index
? {
key: prevState.key,
text: prevState.text,
field: this.props.param,
checked: !prevState.checked
}
: prevState
);
this.setState({ optionsArr });
};
render() {
return (
<div>
Child Component
<div className="menu-item-holder">
{this.state.optionsArr.map((item, i) => (
<div className="menu-item" key={i}>
<Checkbox
name={item.text}
onChange={this.handleItemClick}
checked={item.checked}
label={item.text}
/>
</div>
))}
</div>
<div className="menu-btn-holder">
<Button size="small" onClick={this.submitSelection}>
Apply
</Button>
<Button size="small" onClick={this.clearSelection}>
Cancel
</Button>
</div>
</div>
);
}
}
答案 0 :(得分:2)
这似乎是状态管理不便的情况。当前,状态在子级进行管理,但在父级进行管理将更加容易。这在React中称为lifting state up。
要点-共享状态在父组件中进行管理,并且通过调用传递给子组件的函数来更新共享状态。单击“应用”后,选定的单选值将传递到“父级”,父级会将新选择的值合并到共享状态。
我创建了一个最小的代码示例,展示了如何将状态从子级提升到父级。我还使用了React的一些新功能,例如useState
来简化Child组件。
// Child Component
const Child = ({name, options, updateSelections}) => {
const [selected, setSelected] = React.useState([]);
const handleChange = (event) => {
let updated;
if (event.target.checked) {
updated = [...selected, event.target.value];
} else {
updated = selected.filter(v => v !== event.target.value);
}
setSelected(updated);
}
const passSelectionToParent = (event) => {
event.preventDefault();
updateSelections(name, selected);
}
return (
<form>
{options.map(item => (
<label for={name}>
<input
key={name}
type="checkbox"
name={item}
value={item}
onChange={handleChange}
/>
{item}
</label>
))}
<button onClick={passSelectionToParent}>Apply</button>
</form>
)
}
// Parent Component
class Parent extends React.Component {
constructor(props) {
super(props);
this.fields = ["firstName", "status"],
this.state = {
selected: {}
};
}
getValuesFromKey = (data, key) => {
return data.map(item => item[key]);
}
updateSelections = (name, selection) => {
this.setState({
selected: {...this.state.selected, [name]: selection}
}, () => console.log(this.state.selected));
}
render() {
return (
<div>
{this.fields.map(field => (
<Child
key={field}
name={field}
options={this.getValuesFromKey(this.props.data, field)}
updateSelections={this.updateSelections}
/>
))}
</div>
)
}
}
const data = [
{ firstName: "Jack", status: "Submitted" },
{ firstName: "Simon", status: "Pending" },
{ firstName: "Pete", status: "Approved" },
{ firstName: "Lucas", status: "Rejected" }
];
ReactDOM.render(<Parent data={data}/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0-alpha.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0-alpha.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>
答案 1 :(得分:1)
仅当您隐藏/显示表格时,您的复选框值才会丢失,因为表格会消失
DOM的状态及其子项丢失了。将表装载到DOM后,Child
再次安装组件,以从中获取复选框值来初始化新状态
getValuesFromKey
的方法默认情况下会返回false,清除复选框的刻度。
return {
field: keys[0],
checked: false
};
Stackblitz reproducing the issue。
您必须设置复选框值,以检查selectedValues
对象是否被选中。
return {
field: keys[0],
checked: this.state.selectedValues[key] && this.state.selectedValues[key].includes(keys[0]),
};