React
持久化数据结构
Immutable
每次修改一个immutable对象时都会创建一个新的不可变对象,在新对象上操作并不会影响到源对象的数据
- Persistent Data Structure(持久化数据结构)
- 使用旧数据创建新数据时,要保证旧数据同时可用且不变
- 同时为了避免deepCopy把所有节点都复制一遍带来的性能损耗
- immutable使用了Structural Sharing(结构共享)
- 如果对象树中的一个节点发生变化,仅修改这个节点和受它影响的父节点,其它节点则进行共享
代码示例:
let obj01 = {name: 'name'}
let obj02 = obj01 // 引用复制(浅复制)
let obj03 = {...obj01} // 比浅复制多复制了一层(非严格意义上的深复制,如果展开的是数组等类型而不是字符串等简单类型,那么值也会跟着变化)
let obj04 = {name: 'name', arr: [1, 2, 3]}
let obj05 = JSON.parse(JSON.stringify(obj04)) // 有缺陷的深复制(对象中不能有undefined,否则对应的值会被忽略)
// src/App.jsx
import React from "react";
import {createRoot} from "react-dom/client";
import ImmuTest02 from "./immutable/ImmuTest02";
createRoot(document.getElementById('root')).render(<ImmuTest02/>)
// src/immutable/App.jsx
import React, {useState} from "react";
import {Map} from 'immutable'
/*
let obj = {
name: 'Foo',
age: 24
}
let oldObj = Map(obj)
let newObj = oldObj.set('name', 'Bar')
console.log(oldObj, newObj)
console.log(oldObj.get('name'), newObj.get('name'))
console.log(oldObj.toJS(), newObj.toJS()) 转换为原始对象
*/
export default function App() {
let [state, setState] = useState({
// info: Map({
// name: 'Foo',
// age: 24
// })
info: {
name: 'Foo',
age: 24
}
})
return (
<div>
<button onClick={() => {
// setState({
// info: state.info.set('name', 'Bar').set('age',18)
// })
let old = Map(state.info)
let newImmu = old.set('name', 'Bar').set('age', 18)
setState({
info: newImmu.toJS()
})
}}>Click
</button>
{/* {state.info.get('name')} */}
{/* {state.info.get('age')} */}
{state.info.name}
{state.info.age}
</div>
)
}
// src/Immutable02.jsx
import React, {useState, Component} from "react";
import {Map} from "immutable";
class Child extends Component {
shouldComponentUpdate(nextProps) {
return this.props.filter !== nextProps.filter;
}
render() {
return (
<div>
Child
</div>
)
}
componentDidUpdate() {
console.log('componentDidUpdate')
}
}
export default function Immutable02() {
const [state, setState] = useState({
info: Map({
name: 'Foo',
filter: Map({
text: '1024',
up: true,
down: false
})
})
})
return (
<div>
<button onClick={() => {
setState({
info: state.info.set('name', 'Bar')
})
}}>Click
</button>
{state.info.get('name')}
<Child filter={state.info.get('filter')}/>
</div>
)
}
// src/Immutable03.jsx
import React, {useState} from "react";
import {List} from "immutable";
export default function Immutable03() {
let arr01 = List([1, 2, 3])
let arr02 = arr01.push(4) // 不会影响源数据
let arr03 = arr02.concat([5, 6, 7])
// console.log(arr01, arr02)
console.log(arr01.toJS(), arr02.toJS(), arr03.toJS())
const [state] = useState({
favor: List(['a', 'b', 'c'])
})
return (
<div>
{
state.favor.map(item =>
<li key={item}>{item}</li>)
}
</div>
)
}
// src/immutable/ImmuTest.jsx
import React, {useState} from "react";
import {List, Map} from "immutable";
export default function ImmuTest() {
const [state, setState] = useState({
info: Map({
name: 'Foo',
location: Map({
province: '幻想乡',
city: '博丽神社'
}),
favor: List(['心理学', '哲学', '法学'])
})
})
return (
<div>
{state.info.get('name')}
<br/>
{state.info.get('location').get('province')}-
{state.info.get('location').get('city')}
<br/>
{
state.info.get('favor').map((item, index) =>
<li key={item}>{item}
<button onClick={() => {
setState({
info: state.info.set('favor', state.info.get('favor').splice(index, 1))
})
}}>
删除
</button>
</li>)
}
<button onClick={() => {
setState({
info: state.info.set('name', 'Bar').set('location', state.info.get('location').set('city', '红魔馆'))
})
}}>修改
</button>
</div>
)
}
// src/immutable/ImmuTest02.jsx
import React, {useState} from "react";
import {fromJS} from "immutable";
export default function ImmuTest02() {
const [state, setState] = useState({
info: fromJS({
name: 'Foo',
location: {
province: '幻想乡',
city: '博丽神社'
},
favor: ['心理学', '哲学', '法学']
})
})
return (
<div>
{state.info.get('name')}
<br/>
{state.info.get('location').get('province')}-
{state.info.get('location').get('city')}
<br/>
{
state.info.get('favor').map((item, index) =>
<li key={item}>{item}
<button onClick={() => {
setState({
info: state.info.updateIn(['favor'], (list) => list.splice(index, 1))
// 因为数组的本质就是对象结构的
})
}}>
删除
</button>
</li>)
}
<button onClick={() => {
setState({
info: state.info.setIn(['name'], 'Bar').setIn(['location', 'city'], '红魔馆')
})
}}>修改
</button>
</div>
)
}