React、Redux 和不可变
React, Redux, and Immutable
将 Immutable 与 React(以及可选的 Redux)结合使用有什么优势?在 Redux 中,我可以简单地在我的 reducer 中使用 rest this 来 return 一个新状态:
const initialState = {
activeTrackId: '',
state: 'stopped',
};
export default function (state = initialState, action) {
switch (action.type) {
case actions.PROCESS_TRACK_ACTION:
return {
...state,
activeTrackId: action.state !== 'stopped' ? action.track._id : '',
state: action.state,
};
// ...
我发现它唯一有用的场景是:
shouldComponentUpdate(nextProps) {
const oldProps = Immutable.fromJS(this.props);
const newProps = Immutable.fromJS(nextProps);
return !Immutable.is(oldProps, newProps);
}
据我所知,这甚至可能是滥用它。
也许有人可以启发我在 React 和 Redux 的上下文中使用 Immutable 的优势?
如果你小心,不要改变传递的 属性,你就不必使用 Immutable.js。
由于 props
是引用,因此对其进行任何更改都会影响整个应用程序。
Immutable.js 保证它们不能被修改,但如果你不执行突变,它会对大型应用程序的性能产生影响,但好处是,它可以防止应用程序状态的任何意外污染。
您可以查看 these videos 以获得深入的解释。
Lee 在 2015 年 React Conf 上的演讲中有关于不可变数据的好处和实现的 great video。至于对不可变数据和 React 的思考,我认为它是必不可少的。
除此之外,这里有一些我自己对此事的看法。
精简代码
你的状态变得越复杂,就越难用文字和扩展运算符来管理它。想象一下,你有几层嵌套状态,而不是平坦的:
const initialState = {
core: {
tracker: {
activeTrackId: '',
state: 'stopped'
}
}
};
虽然仍然可以使用展开运算符,但它开始变得乏味了。
return {
...state,
core: {
...state.core,
tracker: {
...state.core.tracker,
activeTrackId: action.state !== 'stopped' ? action.track._id : '',
state: action.state
}
}
};
现在看看 Immutable.js 的等价物。
import { Map } from 'immutable';
const initialState = Map({
core: Map({
tracker: Map({
activeTrackId: '',
state: 'stopped'
})
})
});
然后我们可以使用持久化API对结构进行深度修改
return state
.setIn(
['core', 'tracker', 'activeTrackId'],
action.state !== 'stopped' ? action.track._id : ''
)
.setIn(
['core', 'tracker', 'state'],
action.state
);
值得一提的是,根据状态的形状,拆分和嵌套 reducer 可能更有意义。
结构共享
当您使用 ImmutableJS 对对象进行修改时,它利用了它是通过哈希映射向量实现的这一事实,试图在旧对象和修改后的版本之间共享大部分结构。
当您使用扩展运算符创建新文字时,您被迫复制比生成新对象所需的更多数据。
安全
您可以通过保证对象不会发生变化来消除大量 class 错误。
使用可变状态,可以将对象引用传递给其他代码,这可能会改变它。改变一个对象不是 "an error",所以你不会被告知它已经改变了,也不会有堆栈跟踪,这意味着很难找出改变的来源。
无论您的不可变对象放在哪里,它们都是安全的。
性能
您可以使用不可变数据结构来做出有关是否更新组件的更高级决策。
shouldComponentUpdate(nextProps) {
const oldProps = Immutable.fromJS(this.props);
const newProps = Immutable.fromJS(nextProps);
return !Immutable.is(oldProps, newProps);
}
虽然这些深度比较可能看起来很昂贵,但它们可以防止您在对象未更改时需要比较或触摸 DOM。
如果您的道具本身是不可变对象,这将更加有效,因为 fromJS
不必重新创建嵌套关卡。
将 Immutable 与 React(以及可选的 Redux)结合使用有什么优势?在 Redux 中,我可以简单地在我的 reducer 中使用 rest this 来 return 一个新状态:
const initialState = {
activeTrackId: '',
state: 'stopped',
};
export default function (state = initialState, action) {
switch (action.type) {
case actions.PROCESS_TRACK_ACTION:
return {
...state,
activeTrackId: action.state !== 'stopped' ? action.track._id : '',
state: action.state,
};
// ...
我发现它唯一有用的场景是:
shouldComponentUpdate(nextProps) {
const oldProps = Immutable.fromJS(this.props);
const newProps = Immutable.fromJS(nextProps);
return !Immutable.is(oldProps, newProps);
}
据我所知,这甚至可能是滥用它。
也许有人可以启发我在 React 和 Redux 的上下文中使用 Immutable 的优势?
如果你小心,不要改变传递的 属性,你就不必使用 Immutable.js。
由于 props
是引用,因此对其进行任何更改都会影响整个应用程序。
Immutable.js 保证它们不能被修改,但如果你不执行突变,它会对大型应用程序的性能产生影响,但好处是,它可以防止应用程序状态的任何意外污染。
您可以查看 these videos 以获得深入的解释。
Lee 在 2015 年 React Conf 上的演讲中有关于不可变数据的好处和实现的 great video。至于对不可变数据和 React 的思考,我认为它是必不可少的。
除此之外,这里有一些我自己对此事的看法。
精简代码
你的状态变得越复杂,就越难用文字和扩展运算符来管理它。想象一下,你有几层嵌套状态,而不是平坦的:
const initialState = {
core: {
tracker: {
activeTrackId: '',
state: 'stopped'
}
}
};
虽然仍然可以使用展开运算符,但它开始变得乏味了。
return {
...state,
core: {
...state.core,
tracker: {
...state.core.tracker,
activeTrackId: action.state !== 'stopped' ? action.track._id : '',
state: action.state
}
}
};
现在看看 Immutable.js 的等价物。
import { Map } from 'immutable';
const initialState = Map({
core: Map({
tracker: Map({
activeTrackId: '',
state: 'stopped'
})
})
});
然后我们可以使用持久化API对结构进行深度修改
return state
.setIn(
['core', 'tracker', 'activeTrackId'],
action.state !== 'stopped' ? action.track._id : ''
)
.setIn(
['core', 'tracker', 'state'],
action.state
);
值得一提的是,根据状态的形状,拆分和嵌套 reducer 可能更有意义。
结构共享
当您使用 ImmutableJS 对对象进行修改时,它利用了它是通过哈希映射向量实现的这一事实,试图在旧对象和修改后的版本之间共享大部分结构。
当您使用扩展运算符创建新文字时,您被迫复制比生成新对象所需的更多数据。
安全
您可以通过保证对象不会发生变化来消除大量 class 错误。
使用可变状态,可以将对象引用传递给其他代码,这可能会改变它。改变一个对象不是 "an error",所以你不会被告知它已经改变了,也不会有堆栈跟踪,这意味着很难找出改变的来源。
无论您的不可变对象放在哪里,它们都是安全的。
性能
您可以使用不可变数据结构来做出有关是否更新组件的更高级决策。
shouldComponentUpdate(nextProps) {
const oldProps = Immutable.fromJS(this.props);
const newProps = Immutable.fromJS(nextProps);
return !Immutable.is(oldProps, newProps);
}
虽然这些深度比较可能看起来很昂贵,但它们可以防止您在对象未更改时需要比较或触摸 DOM。
如果您的道具本身是不可变对象,这将更加有效,因为 fromJS
不必重新创建嵌套关卡。