immutable的进阶使用

  • 下面我来展示一下,在深层次的Map或者List结构中,想要修改深层次的数据,如何实现呢?
  • 提供一个思路: 一层一层的改,首先获取第一层数据,再获取第二层数据,通过链式结构的形式修改数据

案例展示:

  • 这个是一个修改信息数据的Demo,使用immutable来实现,但是源数据是一个复杂的Map数据结构
/* ----------------------- 案例组件 --------------------------- */ 
import React, { Component } from 'react'
import { Map, List } from 'immutable'
export default class App extends Component {
state = {
// 将源数据变成Map和List的组合型复杂结构
info: Map({
name: 'Lam',
location: Map({//深层次的Map结构
province: '广东',
city: '江门'
}),
favor: List(['唱', '跳', 'Rap', '篮球'])
})
}
render() {
return (
<div>
<h1>修改地址</h1>
<button onClick={()=>{
// 点击修改深层次的数据
this.setState({
/*
首先获取外层数据,再获取深层数据,最后再修改深层数据,
获取要修改的数据对象,再修改数据本身
*/
// 修改第一层数据
info:this.state.info.set('name','肥林')
// 修改第二层数据(首先修改(获取set)localtion,再获取(get)要修改的数据,最后再修改数据)
.set('location',this.state.info.get('location').set('city','开平'))
})
}}>修改</button>
{/* 展示数据(Map和List) */}
<div>
姓名:{this.state.info.get('name')}
<br />
{/* 链式结构调用深层次的数据 */}
地址:{this.state.info.get('location').get('province')}
-{this.state.info.get('location').get('city')}
<br />
{/* List的循环遍历展示 */}
爱好:{this.state.info.get('favor').map((item, index) => {
return <li key={item}>
{item}
<button onClick={() => {
console.log(index);
// 删除数据(List)
this.setState({
// 获取要修改的数据对象,再修改数据本身
info:this.state.info.set("favor",
this.state.info.get("favor").splice(index,1))
})
}}>删除</button>
</li>
})}
</div>
</div>
)
}
}

结果展示:

image

但是由代码层面我们也可以看出,这样写代码过于复杂,如果数据结构在复杂一点,那么代码量就会非常的多,不利于维护,由此引出下面的解决办法(fromJS的基本使用)

fromJS的基本使用

  • 官方文档

  • fromJS能将一个复杂的数据类型结构转化为Map-List结构(深层次),就不需要我们自己一步一步的再数据中套MapList了,并且里面提供一些方法(setIn,updataIn..),可以帮助我们直接修改深层次里面的数据

修改后的案例代码

import React, { Component } from 'react'
import { fromJS } from 'immutable'
export default class App extends Component {
state = {
// 将源数据变成Map和List的组合型复杂结构
info: fromJS({
name: 'Lam',
location: {//深层次的Map结构
province: '广东',
city: '江门'
},
favor: ['唱', '跳', 'Rap', '篮球']
})
}

// 生命周期
componentDidMount() {
console.log('使用fromJS转化后的数据:',this.state.info)
}

render() {
return (
<div>
<h1>修改地址</h1>
<button onClick={()=>{
// 点击修改深层次的数据
this.setState({
// 修改第一层数据
info:this.state.info.set('name','肥林')
/*
修改第二层数据(使用setIn修改深层次的数据,第一个参数为数组,里面包含数据的层级)
下面就是修改 location 里面的 city 的数据, 修改为开平
*/
.setIn(['location','city'],'开平')
})
}}>修改</button>
{/* 展示数据(Map和List) */}
<div>
姓名:{this.state.info.get('name')}
<br />
{/* 调用深层数据同样可以使用getIn,数组里面的数据一致表示数据层级 */}
地址:{this.state.info.getIn(['location','province'])}
-{this.state.info.getIn(['location','city'])}
<br />
{/* List的循环遍历展示 */}
爱好:{this.state.info.get('favor').map((item, index) => {
return <li key={item}>
{item}
<button onClick={() => {
console.log(index);
// 删除数据(List)使用到updataIn
this.setState({
/*
使用updateIn获取数组的第一层数据,第二个参数为回调函数
用于返回修改后的List
*/
info:this.state.info.updateIn(["favor"],(list)=>list.splice(index,1))
})
}}>删除</button>
</li>
})}
</div>
</div>
)
}
}

结果展示:

image
image

immutable结合redux来使用

  • redux中,修改函数reducer需要保持纯函数的设计,就是对原状态不改变的情况下,将原装态修改成新状态返回出去,因此在redux中集合immutable来使用一般是在reducer中来使用的,但是需要切记修改后的数据在reducer中返回是否为immutable对象,如果是immutable对象则需要使用get()来获取数据展示,set()来修改数据; 如果为普通的对象则直接展示即可。

reducer中返回的是immutable对象

/* ---------------------- reducer(返回immutable对象) ------------------------- */
import { fromJS } from "immutable"// 引入fromJS

// 创建修改store的方法(reducer) 小型最后合并成一个Reducer
/* ----------------保证老状态被immutable保护起来------------ */
const isShowBottomReducer = (prevState=fromJS({// 将源数据改为immutable数据结构
data:''
}),action)=>{
// let newState = {...prevState}// 不再需要使用纯函数写法做数据替换
switch(action.type){
case "getData"://判断修改字段
// newState.data = action.value// 纯函数写法
return prevState.set("show",action.value)// 修改数据后直接返回immutable对象
default:
return prevState
}
}

export default isShowBottomReducer

/* ------------------------------ 调用 ---------------------------------- */
state = {
isShow:store.getState().isShowBottomReducer.get('show')//使用.get获取数据
}
/*
此时在外部调用全局store中的数据时需要使用.get方法来获取,因为你在reducer中返回的是immutable类型的数据
*/

reducer中返回的是普通对象(toJs())[推荐使用]

import { fromJS } from "immutable"// 引入fromJS

// 创建修改store的方法(reducer) 小型最后合并成一个Reducer
const isShowBottomReducer = (prevState={
data:''
},action)=>{
/* ----------------保证老状态被immutable保护起来------------ */
let newState = fromJS(prevState)// 将源数据变成immutable对象
switch(action.type){
case "getData"://判断修改字段
// newState.data = action.value// 纯函数写法(不需要做变量赋值)
//将修改完成后的immutable数据变回普通的js对象(toJS())
return newState.set('data',action.value).toJS()
default:
return prevState
}
}

export default isShowBottomReducer

/* ------------------------------ 调用 ---------------------------------- */
state = {
isShow:store.getState().isShowBottomReducer.show//直接.获取数据
}
/*
此时在外部调用全局store中的数据时直接获取即可,因为你在reducer中返回的是普通的对象类型数据
*/