state
状态
在 Noflux 应用中,“状态”应该被存储在一棵 JavaScript 对象树(Object Tree)中,状态应当是:
不可变的(Immutable)
全局唯一的(单一数据源)
可被序列化的(但不一定完全是)
如果你使用过 Redux,会发现它与 Noflux 在状态管理上有着同样的思想。
不可变
不可变的(Immutable)状态意味着不应当直接修改原始状态,而应当在修改时创建状态的副本。它的好处是可以方便的实现热重载、历史快照等功能。
有许多方式可以实现一个“不可变对象”,如使用 Immutable.js 这样的库,或是使用 ES2015 的 Object.assign 以及 ES2016 的展开运算符(...)。下面是一个例子:
const originObj = {
a: 1,
b: '2',
c: { v: 3},
};
const newObj = { ...originObj, d: 4};这种创建对象副本的方式在 Redux 中经常被使用,但在对较深层次进行修改时会变得很复杂,如这里和下面的例子:
const originObj = {
a: {
b: {
c: [1, 2, 3],
d: 4,
},
},
};
const newObj = {
...originObj,
a: {
...originObj.a,
b: {
...originObj.b,
d: 3,
},
},
};在 Noflux 中对于深层嵌套的修改会很简单,使用 state.get 和 state.set 可以轻易的实现状态读写。
import { state } from '@noflux/react';
state.set({
a: {
b: {
c: [1, 2, 3],
d: 4,
},
},
});
state.set('a.b.d', 5); // same as clone(originObj).a.b.d = 3
state.get(); // return the modified object不仅针对对象,state 同时提供了对于数组的读写所需要的“不可变”操作函数,例如 state.get('a.b.c.1'),将返回 2。参数中描述对象操作的字符串被称为“路径描述字符串”,它的具体用法可见 高级 - state。
state的实现在@noflux/state包(NPM、Github),它封装了 Noflux 所需的状态管理与事件监听。
单一数据源
Noflux 使用 单一数据源 ,在一个 Noflux 应用中通常只有一个全局唯一的 state,这也是为什么我们不需要使用 new 创建 state 而直接引入即可。
import { state } from '@noflux/react';由于 state 是通过闭包在 @noflux/react 中保持的,你可以在任何 .js(或 .jsx) 文件中使用它。在 Noflux 中无需使用 Context 等黑科技获取对 state 的引用。
使用单一数据源的好处在于可以避免状态分散带来管理上的复杂度,同时不可变的、单一的数据源可以方便的实现热重载或历史快照。
但这也意味着任何状态的修改都会创建一个新的对象树,而状态的改变又会触发界面的重新渲染(Re-rendering),随着状态越来越复杂,页面的渲染时间会成倍增加。
不过不用担心,Noflux 使用“写时复制”(Copy-on-write)技术降低创建状态树副本的成本以及 @connect 修饰符智能的避免页面无用的重渲染。对于性能的优化在后文中将做更详细的介绍。
序列化
state 内部维护了一棵对象树,通常这是一个可以被序列化(如JSON.stringify)的纯对象,这意味着通常不应该向 state.set 中传入:
函数(
Function) 或 类(Class)getter或setter具有原型链的的对象
这是因为 Noflux 内部使用了 对象展开运算符(
{ ...obj })和数组展开运算符([...arr])实现,因此只有Own Property才会被克隆。
使用可序列化的状态树还有很多好处:
存储于
localStorage或sessionStorage用于同构渲染
避免嵌套对象中复杂的
this引用
下一步
了解了状态的存储与修改,接下来看一下状态是如何与界面相关联的:React。
Last updated
Was this helpful?