【React】immutable.js 基础教程

用它的原因是为了解决问题:解决项目当中状态大规模管理的深拷贝的问题(防止对象/数组因为引用传递而在使用过程中出现的各种问题)。

JS中数据修改问题

  • 我们先来看一段熟悉的代码:
import React, { Component } from "react";

class App extends Component {
    state = {
        str: "CSDN",
        obj: {
            y: 1,
        },
        arr: [1, 2, 3],
    };
    componentDidMount() {
        const newState = this.state;
        console.log(newState === this.state);
    }
    render() {
        return <div></div>;
    }
}

export default App;
  • 由于js的对象和数组都是引用类型。所以newState的state实际上是指向于同一块内存地址的, 所以结果是newState和state是相等的。
  • 此时,我们尝试修改一下数据:
componentDidMount() {
    const newState = this.state;
    newState.str = "CSDNnb";
    console.log(newState,this.state);
}
  • 可以看到,newState的修改也会引起state的修改(对象是引用传递)。要解决这个问题,js中提供了另一种修改数据的方式,要修改一个数据之前先制作一份数据的拷贝,像这样:
componentDidMount() {
    const newState = Object.assign({}, this.state);
    newState.str = "CSDNnb";
    console.log(newState,this.state);
}
  • 我们可以使用很多方式在js中复制数据,比如:
  • Object.assign, Object.freeze, slice, concat, map, filter, reduce等方式进行复制
  • 但这些都是浅拷贝,就是只拷贝第一层数据,更深层的数据还是同一个引用,比如:
componentDidMount() {
    const newState = Object.assign({}, this.state);
    newState.str = "CSDNnb";
    newState.obj.y = 2;
    newState.arr.push(4);
    console.log(newState,this.state);
}
  • 可以看到,当在更改newState更深层次的数据的时候,还是会影响到state的值。如果要深层复制,就得一层一层的做递归拷贝,这是一个复杂的问题。虽然有些第三方的库已经帮我们做好了,但是深层复制是非常消耗性能的。那么这个问题如何解决呢?这就需要用到immutable.js了。

介绍

不可变数据 (Immutable Data)就是一旦创建,就不能再被更改的数据。对Immutable对象的任何修改或添加删除操作都会返回一个新的Immutable对象。Immutable实现的原理是持久化数据结构(Persistent Data Structure),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免深层拷贝把所有节点都复制一遍带来的s性能损耗,Immutable使用了 结构共享(Structural Sharing),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享(不变)。

在这里插入图片描述

  • 如果上面这张图不能直观的表现出变化,我们可以看下面这张图:
    在这里插入图片描述

  • 使用immutable.js的优缺点:

1. 降低mutable带来的复杂度
2. 节省内存
3. 历史追溯性(版本控制的感觉)。每时每刻的值都被保留了,想回退到哪一步只要简单的将数据取出就行。
4. 拥抱函数式编程。immutable本来就是函数式编程的概念,纯函数式编程的特点就是,只要输入一致,输出必然一致,相比于面向对象,这样开发组件和调试更方便。
  • 缺点
1. 需要重新学习api(我们需要去查阅文档,增加了学习成本)
2. 资源包大小增加(源码大约5000行左右)
3. 容易与原生对象混淆:由于api与原生不同,混用的话容易出错
  • 与其他包一样,immutable.js包默认没有被安装到react中,因此学习使用前需要先进行安装到项目:
npm i -S immutable

常用API

immutable.js提供了许多永久不可变数据结构,包括: ListStackMapOrderedMapSetOrderedSetRecord。为了满足工作开发需求,至少需要掌握以下API(API信息全部来自官网,除了以下体现到的API外,更多API请访问官网):在使用的时候我们只是将其格式在两种之间来回转化,转化之后其就可以帮助我们解决深层拷贝的问题。(序列化与反序列化的感觉)

注意:当前还没有将immutable整合到框架,因此以下api测试的代码不要写在组件中。此处可以另起js文件,让这个js文件被入口文件包含即可。

object转Map对象

import { Map, is } from "immutable";

const state = {
    id: 1,
    name: "张三",
    age: 22,
    mobile: { public: "1300000000", private: "13333333333" },
};
const map1 = Map(state);
const map2 = Map(state);

// 比较上的差异
console.log(map1 === map2);
console.log(map1.equals(map2));
console.log(is(map1, map2));

// 获取上的差异
console.log(state.id);
console.log(state.mobile.private);
console.log(map1.get("id"));
console.log(map1.getIn(["mobile","private"]));

// 修改上的差异
state.name = "王二麻";
console.log(state);
const newMap1 = map1.set("name", "王二麻");
console.log(newMap1.get("name"));
console.log(newMap1.setIn(["mobile", "private"], "13800138000").getIn(["mobile", "private"]));
console.log(newMap1.update("age", (val) => val + 1).get("age"));
console.log(newMap1.updateIn(["mobile", "private"], () => "13888888888").getIn(["mobile", "private"]));

array转List对象

import { List } from "immutable";

const state = ["灞波儿奔", "奔波儿灞"];
let list = List(state);

// 获取
console.log(list.get(0));

// 合并
list = list.concat(["黑鱼精", "鲇鱼怪"]);
console.log(list.get(3));

// 追加
list = list.push("乱石山碧波潭");
console.log(list.get(4));

// 把List对象转成js数组
console.log(list.toArray());

JS转immutable

import { Map, is, fromJS } from "immutable";

const state = {
	id: 1,
	name: "张三",
	age: 22,
	mobile: { public: "1300000000", private: "13333333333" },
};

// 转immutable对象
const immutable = fromJS(state);
console.log(immutable);
// 获取
console.log(immutable.get("name"));
console.log(immutable.getIn(["mobile","private"]));

immutable转JS

import { Map, is, fromJS } from "immutable";

const state = {
	id: 1,
	name: "张三",
	age: 22,
	mobiles: { public: "1300000000", private: "13333333333" },
};

// 转immutable对象
const immutable = fromJS(state);
console.log(immutable.toJS());
  • 注意:toJS方法不需要导入(本身就在map对象的原型上),导入了实际也不会被使用。

Redux中集成

npm i -S redux-immutable
  • 以登录案例为例,步骤如下:
  • (固定)将redux仓库创建入口文件中合并reducer的方法改成redux-immutable提供的合并方法(新方法与之前的是同名的combineReducers)
// 模块化操作

// combineReducers方法是redux中内置的,作用是合并多个reducer和数据源,参数是一个对象,对象中属性值是单个reducer,而其属性名有点类似于vuex模块化时的命名空间的概念
import { createStore, applyMiddleware, compose } from "redux";
// 导入redux-thunk
import thunk from "redux-thunk";
import counter from "./Reducers/counter";
import global from "./Reducers/global";
// 导入redux-immutable提供的合并reducer的方法
import { combineReducers } from 'redux-immutable'

// 解决插件报错的操作
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(
    // 合并多个reducer(整合数据源),不合并会报错
    combineReducers({ counter, global }),
    // 应用中间件
    composeEnhancers(applyMiddleware(thunk))
    // 必须要加上一段插件的配置工具,才能在浏览器中使用redux扩展
    // window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

export default store;
  • 将数据源设置成immutable对象
// 功能模块公用的数据源
// 注意,api都是immutable中提供的,不要导入错了包
import { fromJS } from "immutable";
const state = fromJS({
    _token: "",
});

export default state;
  • 在组件中使用的时候将其转成js对象
// 将数据源的数据映射成当前组件自身的props属性
function mapStateToProps(state) {
    // console.log(state);
    // 返回props对象
    // 这里可以获取整个仓库的数据:state
    // 也可以只要特定模块的数据,例如:state.global
    return state.toJS().global;
}
如果说这里没有使用react-redux,
而是使用的之前的订阅的方式,
则需要在订阅那个位置做数据格式的转化。
  • 在修改的时候使用immutable的api实现修改
// jwt的reducer
import defaultState from "../States/global";

function reducer(state = defaultState, actions) {
    // 判断是否是设置token的操作
    if (actions.type === "set_token") {
        // return { ...state, _token: actions.payload };
        console.log(actions);
        // 修改之后返回新值,可以直接ruturn或者用变量接收再返回
        return state.update("_token", () => actions.payload);
    }
    // 在返回之前写修改数据源的操作
    return state;
}

export default reducer;
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
React Fabric.js是一个用于在React应用中使用Fabric.js库的封装。Fabric.js是一个强大的JavaScript库,用于创建和操作基于HTML5 Canvas的图形对象。通过使用React Fabric.js,您可以轻松地在React应用中创建和操作图形对象,如圆形、矩形、文本等。 要在React应用中使用React Fabric.js,您需要引入Fabric.jsReact Fabric.js的依赖,并在应用程序中创建相应的组件。首先,您需要在您的HTML文件中引入Fabric.js的库文件。然后,您可以使用React的组件生命周期方法,比如componentDidMount,来初始化Fabric.js并在Canvas上绘制图形对象。您还可以使用React的状态管理来更新图形对象的属性。 在React Fabric.js中,您可以使用Fabric.js的API来创建和操作图形对象。例如,您可以使用Fabric.js的Circle类来创建一个圆形对象,并设置其属性,如半径、位置和颜色。然后,您可以将该圆形对象添加到Canvas上,并在React组件中进行渲染。 下面是一个简单的示例代码,展示了如何在React应用中使用React Fabric.js来创建一个圆形对象: ```jsx import React, { Component } from 'react'; import { fabric } from 'fabric'; import './App.css'; class App extends Component { componentDidMount() { const canvas = new fabric.Canvas('canvas'); const circle = new fabric.Circle({ radius: 50, left: 100, top: 100, fill: 'red', }); canvas.add(circle); } render() { return ( <div className="App"> <canvas id="canvas" width={500} height={500}></canvas> </div> ); } } export default App; ``` 在上面的代码中,我们在组件的componentDidMount方法中初始化了Fabric.js的Canvas,并创建了一个半径为50、位于(100,100)的红色圆形对象。然后,我们将该圆形对象添加到Canvas上,并在组件的render方法中渲染Canvas。 通过使用React Fabric.js,您可以方便地在React应用中创建和操作图形对象,实现丰富的可视化效果和交互性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一颗不甘坠落的流星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值