初探immutable Redux+immutable实现todolist
初探immutable Redux+immutable实现todolist
immutable的实现原理是Persistent Data Structrue 持久化数据解构
特点是结构共享带来的性能优化
持久化数据结构
所谓持久化数据结构,就是说,当数据改变时,不会改变原数据,而是返回一个经过改变的新数据。
你可以使用这个新数据,处理拷贝引用类型时属性之间存在引用关系的问题。当然深拷贝也可以处理这个问题,但显然immutable是更高效的方式。
这个特性适用于redux中的reducer
import {Map} from 'immutable'
let map = Map({a:1})
let map1 = map.set({b:2})
console.log(map) // 0: (2) ["a", 1]
console.log(map1) // 0: (2) ["a", 1] 1: Array(2) 0: {b: 2}
结构共享
对immutable来说,基于旧数据返回的新数据,如果新数据的某些节点没有变化,那么会继续沿用,从而到达了尽量复用内存的效果。相比于拷贝所有节点的深克隆来说,immutable在性能上是具有优势的
优点
降低mutable带来的复杂度(引用类型你懂的)
节省内存(结构共享)
时间旅行
函数式编程
缺点
学习api
资源包大小增加
容易与原生对象混淆
使用immutable
Map 数据结构
import { Map } from 'immutable'
const map = Map({
a:1,
b:2,
c:3
})
const obj = {
a:1,
b:2,
c:3
}
//判断是否immutable原生Map
console.log(Map.isMap(map), Map.isMap(obj)) // true false
// get/set 取/存值
List
import { List } from 'immutable'
//初始化
const list = List([1,2,3,4])
//添加
const newList = list.push(5)
//删除,返回新的list,[1,3,4]
const list1 = list.delete(1)
console.log(list,newList)
//不能通过下标取值,只能通过get取值
console.log(list[4],newList[4])
console.log(newList.get(4))//5
//判断类型
console.log(List.isList(newList))
//判断相等
const anotherList = List([1,2,3,4]);
console.log(list === anotherList) /// false
console.log(list.equals(anotherList)) // true
类型比较
如果两个map键值对相同,那么用赋值判断是false
但是用isEquals判断是true
//判断相等
const anotherList = List([1,2,3,4]);
console.log(list == anotherList) /// false
console.log(list === anotherList) /// false
console.log(list.equals(anotherList)) // true
类型转换
import { Map,fromJS } from 'immutable'
const map = Map({
a:1,
b:2,
c:3
})
const obj = {
a:1,
b:2,
c:4
}
const merge = map.merge(map,obj); //合并,相同属性会覆盖
console.log(merge)
console.log(map.toJS())//转成js对象
console.log(map.toObject())//转成js对象
console.log(fromJS(obj))
深层拷贝
import { fromJS } from 'immutable'
const nest1 = fromJS({ a: { b: { c: [3, 4, 5] } } });
const nest2 = nest1.mergeDeep({a:{b:{d:6}}})
//获取值,浅层和深层
console.log(nest2.getIn(['a','b','d']))//这里获取的是a.b.d
//更新值
const n3 = nest2.updateIn(['a','b','d'],value=>value+1);
console.log(n3.getIn(['a','b','d']))//7
redux+immutable实现todolist
为了演示只实现CRUD中的增删,其他实现方式类似
除了react脚手架之外需要的install的插件
- react-redux
- immutable
- redux
1 创建reducer,更新并返回state
使用immuta中的List作为数据结构,返回新state时对于不改变的节点能够保留,达到复用内存优化性能的效果
import { List } from 'immutable'
//初始state
const defaultState = new List([]);
const reducer = (state = defaultState, action) => {
switch (action.type) {
case 'ADD':
return state.push(
{
id: Math.floor(Math.random() * 100),
data: action.data
}
)
case 'DEL':
return state.filter(item => item.id !== action.data)
default:
return state;
}
}
export default reducer;
2 创建store
import { createStore } from "redux";
import reducer from "./reducer";
const store = createStore(reducer)
export default store;
3 连接redux与React组件之一 connect.js
mapState为组件提供状态state,mapDispatch为组件提供方法
import {connect} from 'react-redux'
const mapState = (state)=>{
return {
list:state
}
}
const mapDispatch = (dispatch)=>{
return{
add:(data)=>{
dispatch({
type:"ADD",
data
})
},
del:(data)=>{
dispatch({
type:"DEL",
data
})
}
}
}
export default connect(mapState,mapDispatch);
4 连接redux与React组件之二:入口js文件中Provider包裹todolist组件,提供store
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Todolist from './20-immutable/todolist/Todolist'
import { Provider } from 'react-redux'
import store from './20-immutable/todolist/store/index'
ReactDOM.render(
<Provider store={store}>
<Todolist></Todolist>,
</Provider>,
document.getElementById('root')
);
5 连接redux与React组件之三:高阶组件,connect增强导出
增强导出之后可以用this.props拿到redux store进行后续的渲染与抛发的操作
import React, { Component } from 'react'
import Form from './Form';
import List from './List';
import connect from './store/connect';
class Todolist extends Component {
render() {
return (
<div>
<Form add={this.props.add}></Form>
<List></List>
</div>
)
}
}
export default connect(Todolist);
6 List.jsx
import React, { Component } from 'react'
import connect from './store/connect';
class List extends Component {
handleClick(id){
this.props.del(id)
}
render() {
return (
<ul>
{
this.props.list.map(item => {
return (
<div key={item.id}>
<li >{item.data}</li>
<button onClick={this.handleClick.bind(this,item.id)} >删除</button>
</div>
)
})
}
</ul>
)
}
}
export default connect(List);