由于ReactJS(和其他通量实现,如redux)建议:
我们不应该保持一个可以从其他状态计算的状态(我们称之为派生数据),否则当我们设置状态时,我们必须设置另一个状态。
但请考虑以下示例:
我的页面中有两种状态
- 红绿灯的颜色:灯=红色/绿色
- 是否有人来过马路: people = true (有人)/ false (没有人)
醇>众所周知,当红绿灯处于红灯时,人们无法过马路。
因此,我们有3个正常的组合状态:
- light = green,people = true
- light = green,people = false
- light = red,people = false
醇>另一个状态 light = red且people = true 无效。
当 light = red 时,我们可以计算 people = false ,在这种情况下,人是 light的派生数据。但是当 light = green 时我们不能。
问题是当我设置 light 值时,我必须设置 people 值,否则可能导致无效状态。
那么如何解决这个问题呢?如何设计我的州?
是否有任何图书馆可以帮助管理它们。首先,我可以定义我的状态之间的依赖关系。库是对它们一致性的响应。当我设置一个与他人冲突的状态值时,其他值将被修改为正确的值。
我写了一个简单的例子来展示我想要的东西,有没有像这样的图书馆?
class ComplexState {
constructor(config, initialState){
this.config = config;
this.state = initialState;
this._checkAll();
}
setState(key, value){
var config = this.config[key];
if(config && config.type === ComplexState.Types.Enum){
//Set Enum data type
if(Array.isArray(config.definitionField) && config.definitionField.indexOf(value) !== -1 ||
config.definitionField[value] && typeof config.definitionField[value].checker === 'function' && config.definitionField[value].checker(this.state)){
//Set the value
this.state[key] = value;
//If there is a conflict, modify other values
Object.keys(this.state).forEach(_key => {
if(key === _key){//Self
return;
}
var _value = this.state[_key];
var _config = this.config[_key];
if(!Array.isArray(_config.definitionField) && _config.definitionField[_value] && typeof _config.definitionField[_value].checker === 'function' && !_config.definitionField[_value].checker(this.state)){
//Conflict, adapt to correct value
this.state[_key] = _config.definitionField[_value].adapter(this.state);
}
})
//Check for conflicts
this._checkAll();
}else{
//Invalid value
}
}
}
getState(){
return Object.assign({}, this.state);
}
//Check for conflicts
_checkAll(){
Object.keys(this.state).forEach(_key => {
var _value = this.state[_key];
var _config = this.config[_key];
if(!Array.isArray(_config.definitionField) && _config.definitionField[_value] && typeof _config.definitionField[_value].checker === 'function' && !_config.definitionField[_value].checker(this.state)){
//Conflict
throw new Error('invalid state' + JSON.stringify(this.state));
}
})
}
}
ComplexState.Types = {
Enum : 0
}
使用它,
var myStates = new ComplexState({
light : {
type : ComplexState.Types.Enum,
definitionField : ['red', 'green']
},
people : {
type : ComplexState.Types.Enum,
definitionField : {
'false' : null,
'true' : {
checker : function(state){
return state.light !== 'red';
},
adapter : function(state){
if(state.light === 'red'){
return 'false';
}
return state.people;
}
}
}
}
}, {
light : 'Green',
people : 'false'
})
console.log(myStates.getState());//{light: "Green", people: "false"}
myStates.setState('people', 'true');
console.log(myStates.getState());//{light: "Green", people: "true"}
//when I set light value to red, the people value is automatically set to false
myStates.setState('light', 'red');
console.log(myStates.getState());//{light: "red", people: "false"}
答案 0 :(得分:0)
如果你只需要在设置另一个状态时需要输入值,你可以这样做:
this.setState({
light: someNewColor,
people: someNewColor === red ? false : this.state.people
});
如果someNewColor为红色,则会自动将人设置为false。否则它将保持之前的设定值。
编辑:
如果你想让这个更干净,你必须让人和光完全独立。例如:
this.setState({
light: someNewColor
})
目前这不起作用,因为你无法只用光来计算人。
答案 1 :(得分:0)
我开发了一个库来解决这个问题。 https://github.com/hanjunspirit/cascade.js