我有一个包含多个Views
的应用。每个View
具有一定数量的映射子Entities
。这些实体中的每一个都有一个状态,表示是否折叠/隐藏,称为this.state.show
。每个Entity
都有一个切换show
状态的按钮。 一切正常。
我想做的是在View
上添加一个按钮,该按钮可同时显示或隐藏所有Entities
。我以为这很简单,但是有几个复杂的因素:
Views
,每个应用程序以不同的方式显示相同的数据,因此将show
存储在提升的道具中并不是什么选择。我也不想在文件数据中存储UI状态,因为这使我误入歧途。Entity
的道具直接存储在View
上时,它使我更容易理解发生了什么Entities
的数量会经常更改。这就是为什么我不想将孩子的状态存储在父级中的原因,因为如果我这样做了并且实体发生了变化,那么我就必须以某种方式将道具的更改转换为状态的更改,强烈建议不要这样做。 View
溢出到另一个事件。在这里追求正确的策略是什么?我在想“反应”不够吗?
import React, { Component } from 'react'
import Entity from './Entity.jsx'
import Filter from './Filter.jsx'
class View extends Component {
render() {
return (
<div className="view main">
{this.props.entities ? this.props.entities.map(
(e, i) => (
<Entity
entity={e}
propertyTypes={this.props.propertyTypes}
key={i}
index={i}
taglists={this.props.taglists}
ee={this.props.ee}
/>
)
) : ""}
</div>
)
}
}
export default View
import React, { Component } from 'react'
import Property from './Property.jsx'
import Event from './Event.jsx'
import Relationship from './Relationship.jsx'
class Entity extends Component {
constructor (props) {
super(props);
this.state = {
show: true
}
this.showHide = this.showHide.bind(this)
}
showHide() {
this.setState({
show: !this.state.show
})
}
render() {
return (
<div className="entity" id={this.props.entity.name}>
<div className="entity-header">
<h2>
<input
type="text"
value={this.props.entity.name}
onChange={this.emit}
data-original={this.props.entity.name}
data-index={this.props.index}
data-event="rename"
></input>
</h2>
<button
className="entity-collapse"
data-index={this.props.index}
onClick={this.showHide}
>{this.state.show ? "-" : "+"}</button>
</div>
<div className={this.state.show ? "entity-content" : "entity-content hidden"}>
...
removed for clarity
...
</div>
</div>
)
}
}
export default Entity
答案 0 :(得分:2)
您的状态应仅在父组件中,而不能在任何子组件中。然后,您会将自己的功能和状态作为道具传递给孩子。
答案 1 :(得分:0)
下面是在高阶组件中存储状态的示例。
如果您看一下代码,则只有一个地方存储状态,即View
中的位置,这被称为单一事实来源,这使得React中的编码变得更加简单。
例如,如果您单击all
复选框,将全部选中。而且,如果您逐一检查,all
和none
也会保持同步。
您当然可以将其更改为所需的套件,我在这里使用了复选框,因为很容易看到状态更改起作用。
对于较大的应用程序,真理的单一来源方法变得更加重要,最好避免在React中存储状态。这就是Redux众所周知的,就像我在评论中提到的那样,Redux不是我个人使用的东西,而是使用代理滚动了我自己的真相状态管理源,如果我有时间的话,我可以使用它创建一个NPM模块,因为我确保其他用户会发现它有用。
ps ,.我在示例中使用了React Hooks,因为我相信这是React的未来,但是更改使用类将是微不足道的。
const {useState, cloneElement} = React;
function MultiCheck(props) {
const {checkallto, list, setList} = props;
const checked = !list.some(f => f !== checkallto);
return <div>
<input
onClick={() => {
setList(new Array(list.length).fill(checkallto));
}}
onChange={() => {}}
checked={checked}
type="checkbox"/>
{props.children}
</div>;
}
function View(props) {
const [list, setList] = useState(new Array(props.children.length).fill(false));
function setEntityChecked(ix) {
return (check) => {
const newlist = [...list];
newlist[ix] = check;
setList(newlist);
};
}
const children = props.children.map((
f, ix) => cloneElement(f, {key:ix, checked: list[ix],
setChecked: setEntityChecked(ix)}));
return <div>
<MultiCheck checkallto={true} list={list} setList={setList}>
All
</MultiCheck>
<MultiCheck checkallto={false} list={list} setList={setList}>
None
</MultiCheck>
<hr/>
{children}
</div>;
}
function Entity(props) {
const {checked, setChecked} = props;
return <div><input
checked={checked}
onChange={()=>{}}
onClick={() => setChecked(!checked)}
type="checkbox"/>{props.children}</div>;
}
ReactDOM.render(<React.Fragment>
<View>
<Entity>One</Entity>
<Entity>Two</Entity>
<Entity>Two</Entity>
</View>
</React.Fragment>, document.querySelector('#mount'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="mount"></div>