【问题标题】:React, Redux, and ImmutableReact、Redux 和不可变
【发布时间】:2016-07-06 01:06:06
【问题描述】:

Immutable 与 React(以及可选的 Redux)一起使用有哪些优势?在 Redux 中,我可以简单地在我的 reducer 中使用 rest this 返回一个新状态:

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 的优势?

【问题讨论】:

    标签: reactjs redux immutable.js


    【解决方案1】:

    如果你小心,不要改变传递的属性,你不必使用 Immutable.js。

    由于props 是引用,因此对其进行任何更改都会影响整个应用程序。

    Immutable.js 保证它们不能被修改,但如果你不执行突变,它会对大型应用程序的性能产生影响,但好处是,它可以防止对应用程序状态的任何意外污染。

    您可以查看these videos 以获得深入的解释。

    【讨论】:

      【解决方案2】:

      Lee 在 React Conf 2015 上的演讲中有一个 great video 讨论不可变数据的好处和实现。就不可变数据和 React 的思考而言,我认为这是必不可少的查看。

      除此之外,这里有一些我自己对此事的看法。

      Terser 代码

      你的状态越复杂,就越难用文字和扩展运算符来管理它。想象一下,你有几个层次的嵌套状态,而不是平坦的:

      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
        );
      

      值得一提的是,根据状态的形状,拆分和嵌套减速器可能更有意义。

      结构共享

      当您使用 ImmutableJS 对对象进行修改时,它会利用使用哈希映射向量实现的事实,尝试在旧对象和修改后的版本之间共享大部分结构。

      当您使用扩展运算符创建新的文字时,您必须复制比生成新对象所需的更多的数据。

      安全

      您可以通过保证对象不会发生变异来消除一大类错误。

      使用可变状态,可以将对象引用传递给其他代码,这可能会改变它。改变一个对象不是“错误”,所以你不会被告知它已经改变,也不会有堆栈跟踪,这意味着很难确定突变的来源。

      无论您的不可变对象走到哪里,它们都是安全的。

      性能

      您可以使用不可变数据结构就是否更新组件做出更高级的决定。

      shouldComponentUpdate(nextProps) {
        const oldProps = Immutable.fromJS(this.props);
        const newProps = Immutable.fromJS(nextProps);
      
        return !Immutable.is(oldProps, newProps);
      }
      

      虽然这些类型的深度比较可能看起来很昂贵,但它们可以防止您在对象未更改时需要比较或触摸 DOM。

      如果您的道具本身是不可变对象,这将更加有效,因为fromJS 不必重新创建嵌套级别。

      【讨论】:

      • 很好的答案,丹!这实际上帮助我更多地理解 Immutable。我不确定是使用Map,还是Record,或者如何使用这些东西。我发现文档有时有点混乱。我想知道他们为什么选择使用像.setIn(['core', 'tracker', 'activeTrackId'], value) 这样的格式而不是.setIn('core.tracker.activeTrackId', value)
      • 如果您更喜欢这种表示法,可以使用 dot-prop-immutable 之类的库。
      • PS:更短的,您可以使用Immutable.fromJS 并传递任何内容,它会为您设置正确数量的地图和列表。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-03
      • 2023-04-09
      • 1970-01-01
      • 2016-02-22
      • 2018-06-23
      • 2018-07-07
      • 2017-02-27
      相关资源
      最近更新 更多