我目前正在研究React JSReact Native个框架.在中途,当我读到Facebook的Flux和Redux实现时,我遇到了不变性或Immutable-JS library.

问题是,为什么不变性如此重要?变异对象有什么不对?这不是让事情变得简单吗?

举个例子,让我们考虑一个简单的News reader应用程序,它的开始屏幕是新闻标题的列表视图.

比方说,如果我设置了值为initiallyarray of objects,我就不能对其进行操作.这就是不变性原则所说的,对吧?(如果我错了,请纠正我.) 但是,如果我有一个必须更新的新的News对象怎么办?通常情况下,我可以只将对象添加到数组中. 在这种情况下,我该如何实现?是否删除该存储并重新创建? 将对象添加到数组不是更便宜的操作吗?

推荐答案

我最近一直在研究同一个话题.我会尽我所能回答你的问题,并try 分享到目前为止我所学到的东西.

问题是,为什么不变性如此重要?这有什么问题吗

基本上,它归结为这样一个事实:不变性(间接地)提高了可预测性和性能,并允许进行Mutations 跟踪.

Predictability

Mutations 隐藏了变化,而变化会产生(意想不到的)副作用,从而导致讨厌的虫子.当您强制执行不变性时,您可以保持应用程序架构和心智模型的简单,这使您更容易对应用程序进行推理.

Performance

即使向不可变对象添加值意味着需要创建一个新实例,其中需要复制现有值,并且需要向新对象添加新值,这会消耗内存,但不可变对象可以利用 struct 共享来减少内存开销.

所有更新都会返回新值,但内部 struct 会共享给

你可以阅读更多关于这here的信息.

Mutation Tracking

除了减少内存使用,不变性还允许您通过使用引用和值相等来优化应用程序.这就很容易看出是否有什么变化.例如,react组件中的状态更改.可以使用shouldComponentUpdate通过比较状态对象来判断状态是否相同,并防止不必要的渲染.

额外资源:

如果我设置一个数组,比如一个初始值为的对象array.我不能

是的,这是正确的.如果你对如何在你的应用程序中实现这一点感到困惑,我建议你看看redux是如何做到这一点的,以熟悉核心概念,这对我有很大帮助.

我喜欢以Redux为例,因为它包含不变性.它有一个单一的不可变状态树(称为store),其中所有状态更改都是通过调度操作显式进行的,这些操作由一个reducer处理,reducer接受前一个状态和所述操作(一次一个),并返回应用程序的下一个状态.你可以阅读更多关于它的核心原则here.

有一个关于egghead.io的优秀redux课程,其中redux的作者Dan Abramov解释了以下原则(为了更好地适应场景,我对代码进行了一些修改):

import React from 'react';
import ReactDOM from 'react-dom';

// Reducer.
const news = (state=[], action) => {
  switch(action.type) {
    case 'ADD_NEWS_ITEM': {
      return [ ...state, action.newsItem ];
    }
    default: {
        return state;
    }
  }
};

// Store.
const createStore = (reducer) => {
  let state;
  let listeners = [];

  const subscribe = (listener) => {
    listeners.push(listener);

    return () => {
      listeners = listeners.filter(cb => cb !== listener);
    };
  };

  const getState = () => state;

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach( cb => cb() );
  };

  dispatch({});

  return { subscribe, getState, dispatch };
};

// Initialize store with reducer.
const store = createStore(news);

// Component.
const News = React.createClass({
  onAddNewsItem() {
    const { newsTitle } = this.refs;

    store.dispatch({
      type: 'ADD_NEWS_ITEM',
      newsItem: { title: newsTitle.value }
    });
  },

  render() {
    const { news } = this.props;

    return (
      <div>
        <input ref="newsTitle" />
        <button onClick={ this.onAddNewsItem }>add</button>
        <ul>
          { news.map( ({ title }) => <li>{ title }</li>) }
        </ul>
      </div>
    );
  }
});

// Handler that will execute when the store dispatches.
const render = () => {
  ReactDOM.render(
    <News news={ store.getState() } />,
    document.getElementById('news')
  );
};

// Entry point.
store.subscribe(render);
render();

此外,这些视频还进一步详细演示了如何实现以下各项的不变性:

Javascript相关问答推荐

如何避免使用ajax在Vue 3合成API中重定向

在具有焦点和上下文的d3多线图表中,如何将上下文的刷新限制在特定日期?

布局样式在刷新时不持续

在JavaScript中,是否有一种方法可以创建自定义thable,在等待某些代码后自动触发它?

容器如何更改默认插槽中子项的显示?

在贝塞尔曲线的直线上找不到交叉点:(使用@Pomax的bezier.js)

了解Node.js中的EventEums和浏览器中的addEventEums之间的关系

使用javascript将Plotly Expandable Sparkline转换为HighCharter Plot在bslib卡中

如何禁用附加图标点击的v—自动完成事件

在服务器上放置了Create Reaction App Build之后的空白页面

为什么Mutations 观察器用微任务队列而不是macrotask队列处理?

JSDoc创建并从另一个文件导入类型

如果Arrow函数返回函数,而不是为useEffect返回NULL,则会出现错误

使用Google API无法进行Web抓取

对网格项目进行垂直排序不起作用

如何在不影响隐式类型的情况下将类型分配给对象?

是否可以将异步调用与useState(UnctionName)一起使用

为列表中的项目设置动画

如何在下一个js中更改每个标记APEXCHARTS图表的 colored颜色

如何在Web项目中同步语音合成和文本 colored颜色 更改