通过my previous question我了解到React会自动保留子组件的状态,这就是its documentation says的原因:
什么不应该进入状态?
反应组件:根据底层道具和状态在render()中构建它们。
现在我的问题是如何为我们隐藏的组件做同样的事情?
考虑一个子组件,它在迭代中不会被显示,同时我们希望在将来恢复时保留其状态!
为了说明我的确切含义,我设计了一个案例场景来向您展示。在以下代码中,您可以添加有状态子组件。为每个组件提供了一个复选框,以便您可以标记它们。最后,第三个按钮将隐藏未标记的子组件。我正在寻找一种方法来恢复未标记组件的状态。
class BlackBox extends React.Component
{
constructor() {
super();
this.state = {
checked: false,
counter: 0,
};
}
increment = () => {
this.setState(Object.assign({}, this.state, { counter: this.state.counter+1 }));
};
switch = () => {
this.setState(Object.assign({}, this.state, { checked: !this.state.checked }));
};
isChecked() {
return this.state.checked;
}
render() {
return (
<span onClick={this.increment} title={this.props.id} style={{
fontSize: '24pt',
border: '1px solid black',
margin: 10,
padding: 10,
}}>
<input type="checkbox" onChange={this.switch} checked={this.state.checked} />
{this.state.counter}
</span>
);
}
}
class RedBox extends React.Component
{
constructor() {
super();
this.state = {
checked: false,
counter: 0
};
}
increment = () => {
this.setState(Object.assign({}, this.state, { counter: this.state.counter+1 }));
};
switch = () => {
this.setState(Object.assign({}, this.state, { checked: !this.state.checked }));
};
isChecked() {
return this.state.checked;
}
render() {
return (
<span onClick={this.increment} title={this.props.id} style={{
fontSize: '24pt',
border: '1px solid red',
margin: 10,
padding: 10,
}}>
<input type="checkbox" onChange={this.switch} checked={this.state.checked} />
{this.state.counter}
</span>
);
}
}
class Parent extends React.Component {
static blackCount = 0;
static redCount = 0;
state = {
childCmps: [],
showOnlyChecked: false,
};
constructor(props, context) {
super(props, context);
}
addBlackBox = () => {
this.setState(Object.assign({}, this.state, {
childCmps: [...this.state.childCmps, { Component: BlackBox, id: "black" + (++Parent.blackCount) }],
}));
};
addRedBox = () => {
this.setState(Object.assign({}, this.state, {
childCmps: [...this.state.childCmps, { Component: RedBox, id: "red" + (++Parent.redCount) }],
}));
};
showHide = () => {
this.setState(Object.assign({}, this.state, {
showOnlyChecked: !this.state.showOnlyChecked,
}));
};
render() {
let children = this.state.childCmps.map(child => <child.Component key={child.id} id={child.id} ref={child.id} />);
return (
<div>
<button onClick={this.addBlackBox}>Add Black Box</button>
<button onClick={this.addRedBox}>Add Red Box</button>
<button onClick={this.showHide}>Show / Hide Unchecked</button>
<br /><br />
{children.filter(box => !this.state.showOnlyChecked || this.refs[box.props.id].isChecked())}
</div>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById("root")
);
答案 0 :(得分:3)
答案简短:
没有解决方案只有优点而且没有缺点(在现实生活中和你的问题中) 你真的只有3个选择:
您可能想要查看redux以使用商店。
答案很长
如果你想
然后你不能把它保持在儿童状态。根据定义,State绑定到组件的生命周期。如果从DOM(= unmounted)中删除它,那么您将丢失所有状态信息。
因此,如果您想保存此信息,则必须将此信息移至父组件的状态(显然对于每个孩子)。
您可以找到working codepen here。
关于此代码的其他一些注意事项:
<...Box>
组件现在变得纯粹=无状态组件onCheck()
和onClick()
),它们将从状态更新数组中的特定对象。需要一些特殊的摆弄以确保我们不会在这里直接改变状态。setState()
,您不需要执行Object.assign()
并再次传递所有状态。如果为对象提供仅更改的参数,则react将保持其他参数不变。答案 1 :(得分:0)
而不是完全从DOM中移除组件(正如您在filter
中所做的那样),只需隐藏它。将children.filter
替换为以下内容:
{children.map((box, idx) => {
var show = !this.state.showOnlyChecked || this.refs[box.props.id].isChecked();
return <span key={idx} style={{display: (show? 'inline-block': 'none')}}>{box}</span>;
})}