React入门(十一)之immutable

一、immutabl

1.1、Immutable.js介绍

更多详情请参考 immutable官方文档
还可以参考 这一篇博客

总的来说,immutable就是用来解决内存浪费的问题。

Immutable( 不可改变的 ) Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。

Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享

1.2、Immutable优缺点

  • 优点

    减少内存的使用(深拷贝消耗内存)

    并发安全

    降低项目的复杂度

  • 缺点

    库的大小(建议使用seamless-immutable)

    对现有项目入侵严重

    容易与原生的对象进行混淆

1.3、Immutable 中常用类型(Map,List)

1.3.1、Map

作用:复制一个对象(键值对)

参数:json对象

返回值:Map对象(经过immutable包装了的Map对象) ,该Map对象也可以使用set,get方法。但是set方法调用后会产生一个新的Map对象。

Immutable.Map(json对象);

示例:

npm i --save immutable

function f(){
    //定义一个对象obj1
     var obj1 = {
        id:"007",
        name:"张三疯",
        address:{
            province:"陕西省",
            city:"西安市"
        }
    };
    //浅复制:let obj2 = obj1;  两个对象会共享同一块内存区域
    //深拷贝:两个对象的内存是独立的,
    
    //使用Immutable.Map()进行复制,相同的数据会共享。
    let obj2 = Immutable.map(obj1).toJS();
    //修改数据时,只把改动数据及其父级数据部分进行复制,其它部分不做复制,依然共享,节约了内存。
    obj1.address.province="北京";
    console.log(obj1);//obj1.address.province是北京
    console.log(obj2);//obj2.address.province是陕西
}

Map对象的set函数会产生一个新的对象

示例:

function f(){
   var obj1 = {
        id:"007",
        name:"张三疯"
    };

  let obj2 = Immutable.Map(obj1);  
    
  let obj3 = obj2.set("name","李思峰");  
  let obj4 = obj2.set("sex","男");

  console.log(obj2.toJS());   //{id: "007", name: "张三疯"}
  console.log(obj3.toJS());    //{id: "007", name: "李思峰"}
  console.log(obj4.toJS());    //{id: "007", name: "张三疯", sex: "男"}
}

1.3.2、List

可重复的有序列表,对应Array

作用:复制一个数组

参数:数组

返回值:List。

是有序的索引密集集合,类似于JavaScript数组,针对List类型有set和get方法,分别表示设置和获取

function f(){
  const persons = ['芙蓉姐姐','春哥','犀利哥']
  let ipersons = Immutable.List(persons);
  
  let ipersons2 = ipersons.set( 1, '干露露');

  console.log("ipersons",ipersons);//List对象
  console.log("ipersons.toJS()",ipersons.toJS()) 

  console.log("ipersons2",ipersons2);//List对象
  console.log("ipersons2.toJS()",ipersons2.toJS()) 
}

1.4、Immutable 中常用方法

(1) Immutable.fromJs()//把一个js对象(数组)转化为Immutable对象。
    let obj = Immutable.fromJS({ a: 1,b: 1,c: 1 });
    console.log(obj);
    let arr = Immutable.fromJS(['芙蓉姐姐','春哥','犀利哥']);
     console.log(arr);

(2) immutable对象.toJS()//把一个Immutable对象转化为js对象(数组)。
 	 let o =  obj.toJS();
     console.log(o);
	 let arr2 = arr.toJS();
      console.log(arr2);

(3) Immutable.is():
//比较两个Map(或List)的值是否相等
   var map1 = Immutable.Map({ a: 1,b: 1,c: 1 }); 
   var map2 = Immutable.Map({ a: 1,b: 1,c: 1 });
   console.log(Immutable.is(map1, map2));

1.5、Immutable + Redux 的开发方式

redux中的state也是用immutable的方式,就需要使用redux-immutable提供的combineReducers来代替。

//创建仓库

import {combineReducers} from 'redux-immutable';
import { createStore } from "redux";

import reducer from "../store/reducer";


let rootReducers = combineReducers({reducer});

let store = createStore(rootReducers);

export default store;

reducers中的state也需要使用immutable

//reducer

// 初始化reducer中的initialState时建议用List方法而不是fromJS方法,效率更高
import Immutable from "immutable";

let initState=Immutable.List([
    {
        text:"吃饭",
        isComplete:false
    },
    {
        text:"睡觉",
        isComplete:true
    }
])

export default (state=initState,action)=>{
    //let state1 = state.toJS();
    let {type,payload} = action;
    switch(type){
        case "ADDTODO":{
            let obj = {
                text:payload,
                isComplete:false
            }
            return Immutable.set(state.size,obj]);
        }
        default:return state;
    }
}

组件里面,获取到数据后,就需要使用toJS()进行转换。或者使用immutable的函数进行操作。

组件:
class App extends React.Component {
  constructor(props){
    super(props);
    console.log("store.getState()",store.getState().toJS().reducer);
    this.state ={
        todos:store.getState().toJS().reducer,
        text:""
    }
  }

  componentDidMount(){
    store.subscribe(()=>{
      this.setState({
        todos:store.getState().toJS().reducer
      })
    });
  }
 …………………………

二、mobx

===》 使用文档,点击查看

2.1、介绍

类似于redux的一套数据流方案。

Flux思想单向数据流方案,以 Redux 为代表;
Reactive响应式数据流方案,以 Mobx 为代表;

  • 单向数据流实现:redux + react-redux + react-thunk

  • 响应式数据流实现:mobx + mobx-react

​ MobX 是通过观察者模式对数据进行追踪处理,在对可观察属性作出变更或者引用的时候,触发其依赖的监听函数,整体的store注入机制采用react提供的context来进行传递

2.2、装饰器Decorator

是个函数,用来装饰类或者类成员 ,是Object.defineProperty的语法糖

//给对象添加或修改属性
Object.defineProperty(target, prop, desc)
//target 需要定义属性的当前对象
//prop 当前需要定义的属性名 类型:字符
desc默认值说明
configurablefalse描述属性是否可以被删除,默认为 false
enumerablefalse描述属性是否可以被for…in或Object.keys枚举,默认为 false
writablefalse描述属性是否可以修改,默认为 false
getundefined当访问属性时触发该方法,默认为undefined
setundefined当属性被修改时触发该方法,默认为undefined
valueundefined属性值,默认为undefined
//定义装饰器(以下代码会被转成Object.defineProperty的写法)
function 装饰器名 (target,prop,descriptor){
  descriptor.writable=false;//writable属性是否可以写入
}

//使用装饰器
@装饰器名 类
@装饰器名 实例属性|静态属性(类的属性)
@装饰器名 实例方法|静态方法(类的方式)

//使用场景
mobx / angluarTs / vueTs / reactTs / java ...

配置

create-react-app脚手架 不支持装饰器语法,需要配置

yarn add @babel/plugin-proposal-decorators --save

package.json

babel: {
  "presets":...

  +
  "plugins": [
      ["@babel/plugin-proposal-decorators", { "legacy": true }],
   ]

  ....
}

vscode编辑配置

vscode->文件->首选项-->设置->搜索:experimentalDecorators->勾上
//webstrom 无需设置

示例代码:

定义一个只读装饰器(其实就是个函数),设定属性是只读的。
function  readonly(target,prop,desc) {
  desc.writable = false;
}

class Dog{
  //使用装饰器,修饰dark属性为只读的
  @readonly dark="wangwang";
}


let d =  new Dog();
d.dark="mie"; //这个是不能修改成功的
console.log(d.dark);

2.3、mobx成员

observable 装饰类和其成员

@observable 装饰store类的成员,让store中的成员成为被观察者,即:在组件里可以订阅该数据的变化。

Mbox的思想是:把state和reducer都放在一个类中。state就是数据,reducer就是方法。

import { observable } from 'mobx';
//1)、定义状态并使其可观察
//state:(在对象外面套上observable()函数,就可以,让对象里的数据可以被订阅)
let appStore = observable({
    count:0
});

appStore.increment = function () {
    console.log("increment");
    appStore.count += 1;
}

export default appStore;

2.4、mobx-react成员

Provider inject observer

Provider,顶层提供appStore的服务

<Provider appStore={appStore}>

</Provider>

inject:在组件里使用仓库对象(appStore)。 Provider和inject结合起来,就可以让顶层提供的仓库对象(appStore)在组件里使用

@inject('appStore')
class Index extend React.Component{
     render(){
         <div>
         	{this.props.appStore.属性名}
         </div>
     }
}

observer:能够监听到数据的变化,并响应到组件里。即:在组件里订阅了store中的数据,当store中的数据发生变化时,就会发布给组件。

@observer
class Index extend React.Component{
     render(){
         <div>
         	{this.props.appStore.属性名}
         </div>
     }
}

2.5、Mobx 的使用

1、安装:

npm install mobx --save   或者  yarn  add  mobx 

2、创建仓库

文件名: ./mobxstore/index.js

import { observable } from 'mobx';
//1)、定义状态并使其可观察
//state:(在对象外面套上observable()函数,就可以,让对象里的数据可以被订阅)

const appStore = observable({
    count: 0
});

appStore.increment = function () {
    console.log("increment");
    appStore.count += 1;
}

export default appStore;

3、入口文件:

在顶层提供 仓库对象(appStore)

//index.js

import appStore from './mobxstore';
import { Provider } from "mobx-react";

ReactDOM.render(
  <BrowserRouter>
    <Provider appStore = {appStore}>
      <Route path="/" component={App} />
    </Provider>
  </BrowserRouter>,
  document.getElementById('root')
);

4、使用数据的组件

需要使用 observer,inject

import { Component } from "react";
import {observer,inject} from "mobx-react";

@inject('appStore')  // 使用appStore对象,对应着顶层组件的Provider提供的appStore
@observer   //监听appStore中数据的变化,即:只要appStore中的数据发生变化,就会重新渲染该组件
class Index extends Component {    
    //这个不能用箭头函数     
    render(){
        return(
                <div>
                    count:{this.props.appStore.count}                    
                </div>
            )
    }
}

export default Index;

5、修改数据的组件:

需要使用 inject

import {observer,inject} from "mobx-react";

@inject('appStore')  // 使用appStore对象,对应着顶层组件的Provider提供的appStore
export default class Layout extends Component {

    incCount(){
        this.props.appStore.increment();
    }
    
    render = () => (
        <div className="box">
          <input type="button" value=" 加 " onClick={this.incCount.bind(this)} />                 
        </div>
    )
}

注意:如果提示以下内容:

Parsing error: Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.

请安装:

npm install --save-dev babel-plugin-transform-decorators-legacy
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React 是一个用于构建用户界面的 JavaScript 库。它被 Facebook 开发,用于构建 Facebook 和 Instagram 等应用程序的用户界面。React 通过组件化的方式构建用户界面,使得代码更易于维护和复用。下面是一个简单的 React 入门指南: 1. 安装 React React 可以通过 NPM 安装,可以在命令行中执行以下命令来安装 React: ``` npm install react react-dom ``` 2. 创建 React 组件 在 React 中,一个组件就是一个 JavaScript 类。下面是一个简单的组件示例: ```javascript import React from 'react'; class HelloWorld extends React.Component { render() { return <div>Hello World!</div>; } } export default HelloWorld; ``` 这个组件只是简单地渲染一个 `Hello World!` 的文本。 3. 渲染组件 要在页面中渲染组件,需要使用 `ReactDOM.render()` 方法。下面是一个简单的示例: ```javascript import React from 'react'; import ReactDOM from 'react-dom'; import HelloWorld from './HelloWorld'; ReactDOM.render( <HelloWorld />, document.getElementById('root') ); ``` 这个示例中,我们首先导入了 `ReactDOM` 和 `HelloWorld` 组件,然后使用 `ReactDOM.render()` 方法将 `HelloWorld` 组件渲染到页面上。在这个示例中,我们将组件渲染到了一个 ID 为 `root` 的元素中。 这只是 React入门React 还有很多其他的概念和功能,比如 JSX、状态、生命周期等等。如果您想深入了解 React,可以查看 React 官方文档,里面有很多有用的信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值