React immer與Redux Toolkit使用教程詳解
1. immer
概述:
它和immutable相似的,實(shí)現(xiàn)了操作對(duì)象的數(shù)據(jù)共享,可以優(yōu)化性能。它實(shí)現(xiàn)的原理使用es6的Proxy完成的。小巧,沒有像immutable哪樣有新數(shù)據(jù)類型,而是使用js類型。
安裝:
yarn add immer@9
1.1 setState結(jié)合immer使用
簡(jiǎn)單使用:
import React from 'react'
// 把源數(shù)據(jù)使用Proxy進(jìn)行代理處理,后面就可以精準(zhǔn)的去找到變化的數(shù)據(jù)
import { produce } from 'immer'
const state = {
count: 1
}
// 進(jìn)行代理后,并修改
// draft就是代理對(duì)象,它就是state代理對(duì)象
const newState = produce(state, draft => {
draft.count++
})
console.log(newState.count)// 2
const App = () => {
return <div></div>
}
export default App使用immer進(jìn)行proxy代理,源數(shù)據(jù)中只有變化的了的數(shù)據(jù)才更新,沒有變化則共享,這樣做可以提高性能:
import React from 'react'
// 把源數(shù)據(jù)使用Proxy進(jìn)行代理處理,后面就可以精準(zhǔn)的去找到變化的數(shù)據(jù)
import { produce } from 'immer'
const baseState = {
arr: [1, 2, 3],
obj: { id: 1, name: '張三' }
}
// 使用immer進(jìn)行proxy代理,源數(shù)據(jù)中只有變化的了的數(shù)據(jù)才更新,沒有變化則共享,提高性能
const newState = produce(baseState, draft => {
draft.arr.push(4)
})
// 當(dāng)前只修改數(shù)組,對(duì)象沒有修改,共享
console.log('arr', newState.arr === baseState.arr) // false
console.log('obj', newState.obj === baseState.obj) // true
const App = () => {
return <div></div>
}
export default App
使用 immer 優(yōu)化 setState 使用:
import React, { Component } from 'react'
import { produce } from 'immer'
// 優(yōu)化setState更新數(shù)據(jù)
class App extends Component {
state = {
count: 100,
carts: [
{ id: 1, name: 'aa', num: 1 },
{ id: 2, name: 'bb', num: 2 }
]
}
addCount = () => {
// 原來(lái)的寫法
// this.setState(state => ({ count: state.count + 1 }))
// 使用immer來(lái)優(yōu)化setState操作
this.setState(
produce(draft => {
// 不用返回,返加不允許,draft它是一個(gè)代理對(duì)象,修改后,它能監(jiān)聽到數(shù)據(jù)的變化,更新視圖
draft.count++
})
)
}
render() {
return (
<div>
<h3>{this.state.count}</h3>
<button onClick={this.addCount}>++++++</button>
<hr />
{this.state.carts.map((item, index) => (
<li key={item.id}>
<span>{item.name}</span>
<span>---</span>
<span>
{item.num} --
<button
onClick={() => {
this.setState(
produce(draft => {
// draft它就是當(dāng)前的this.state
draft.carts[index].num++
})
)
}}
>
++++
</button>
</span>
</li>
))}
</div>
)
}
}
export default App
1.2 useState結(jié)合immer使用
import React, { useState } from 'react'
import { produce } from 'immer'
const App = () => {
// 普通的數(shù)字,不是proxy代理,proxy代理的是對(duì)象
// 如果它是一個(gè)普通值,沒有必要使用immer來(lái)完成優(yōu)化操作
let [count, setCount] = useState(100)
// 對(duì)象類型才是使用immer工作的場(chǎng)景
let [carts, setCarts] = useState([
{ id: 1, name: 'aa', num: 1 },
{ id: 2, name: 'bb', num: 2 }
])
return (
<div>
<h3>{count}</h3>
<button
onClick={() => {
// 之前的寫法
// setCount(v => v + 1)
setCount(produce(draft => draft + 1))
}}
>
+++count+++
</button>
<hr />
<button
onClick={() => {
setCarts(
produce(draft => {
draft.push({ id: Date.now(), num: 1, name: 'aaaa--' + Date.now() })
})
)
}}
>
添加商品
</button>
{carts.map((item, index) => (
<li key={item.id}>
<span>{item.name}</span>
<span>---</span>
<span>
{item.num} --
<button
onClick={() => {
setCarts(
produce(draft => {
// 不能返回,寫上去感覺就像在vue的感覺
draft[index].num++
})
)
}}
>
++++
</button>
</span>
<span
onClick={() => {
setCarts(
produce(draft => {
draft.splice(index, 1)
})
)
}}
>
刪除
</span>
</li>
))}
</div>
)
}
export default App

1.3 immer和redux集合
redux/index.js:
import { createStore } from 'redux'
import { produce } from 'immer'
const initState = {
count: 100
}
// 以前的寫法
/* const reducer = (state = initState, { type, payload }) => {
if ('add' === type) {
// 深復(fù)制
return { ...state, count: state.count + payload }
}
return state
} */
const reducer = produce((draft, { type, payload }) => {
// 寫法就和vuex中的mutation中的寫法一樣的,簡(jiǎn)化了
// 操作數(shù)據(jù)無(wú)需深復(fù)制,提升性能
if ('add' === type) draft.count += payload
}, initState)
export default createStore(reducer)前端頁(yè)面:
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
const App = () => {
const dispatch = useDispatch()
const count = useSelector(state => state.count)
return (
<div>
<h3>{count}</h3>
<button
onClick={() => {
dispatch({ type: 'add', payload: 2 })
}}
>
++++
</button>
</div>
)
}
export default App
2. Redux Toolkit
概述:
它開箱即用的高效 Redux 開發(fā)工具集,是 redux 新的庫(kù),也是官方推薦今后在項(xiàng)目中使用的 redux 庫(kù),內(nèi)置了immer、redux-thunk和redux-devtools。
安裝:
yarn add @reduxjs/toolkit react-redux
使用:
前臺(tái)頁(yè)面:
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
const App = () => {
const dispatch = useDispatch()
const count = useSelector(state => state.count)
return (
<div>
<h3>{count}</h3>
<button
onClick={() => {
dispatch({ type: 'add', payload: 2 })
}}
>
++++
</button>
</div>
)
}
export default Appredux入口文件:
import { configureStore } from '@reduxjs/toolkit'
// 上來(lái)它就是分模塊,在項(xiàng)目中,所以的數(shù)據(jù)一定是分模塊來(lái)管理的
import count from './modules/count'
import user from './modules/users'
export default configureStore({
reducer: {
count,
user
}
})同步操作(count.js):
import { createSlice } from '@reduxjs/toolkit'
// 同步操作
const countSlice = createSlice({
// 命名空間名稱,比redux中更好,redux沒有
// 它的名稱要和入口文件中configureStore中的reducer配置對(duì)象中的key名稱要一致
name: 'count',
// 初始化數(shù)據(jù)源
initialState: {
num: 10
},
// 修改數(shù)據(jù)源的方法集合
reducers: {
// 組件中派發(fā)dispatch(setNum(2)) // 2就會(huì)給payload
// state它就是proxy對(duì)象[immer]
setNum(state, { payload }) {
state.num += payload
}
}
})
// 導(dǎo)出給在組件中調(diào)用
export const { setNum } = countSlice.actions
// 把當(dāng)前模塊的reducer導(dǎo)入,集合到大的reducer中
export default countSlice.reducer異步操作(users.js):
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
// 方案2
// 寫在上面,進(jìn)行網(wǎng)絡(luò)請(qǐng)求
export const fetchUser = createAsyncThunk('user/fetchUser', async page => {
// 實(shí)現(xiàn)異步數(shù)據(jù)獲取
let ret = await (await fetch('/api/users?page=' + page)).json()
// return 中的數(shù)據(jù)就是返回到state中的users中的數(shù)據(jù) 一定要return
return ret.data
})
// 異步操作
const userSlice = createSlice({
name: 'user',
initialState: {
users: []
},
reducers: {
setUsers(state, { payload }) {
state.users = payload
}
},
// 解決異步
extraReducers: builder => {
// 模擬了promise的3個(gè)狀態(tài),只取成功狀態(tài) fulfilled
// payload中的數(shù)據(jù)就是fetchUser方法它return出來(lái)的數(shù)據(jù)
builder.addCase(fetchUser.fulfilled, (state, { payload }) => {
state.users = payload
})
}
})
export const { setUsers } = userSlice.actions
// 網(wǎng)絡(luò)請(qǐng)求 --- 內(nèi)置redux-thunk所以,就可以在此處完成異步操作 -- 我推薦的
// 方案1
export const fetchThunkUser = () => async dispatch => {
let ret = await (await fetch('/api/users')).json()
dispatch(setUsers(ret.data))
}
export default userSlice.reducer
到此這篇關(guān)于React immer與Redux Toolkit使用教程詳解的文章就介紹到這了,更多相關(guān)React immer與Redux Toolkit內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React實(shí)現(xiàn)全局組件的Toast輕提示效果
這篇文章主要介紹了React實(shí)現(xiàn)全局組件的Toast輕提示效果,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
React項(xiàng)目中動(dòng)態(tài)插入HTML內(nèi)容的實(shí)現(xiàn)
本文主要介紹了React項(xiàng)目中動(dòng)態(tài)插入HTML內(nèi)容的實(shí)現(xiàn),通過(guò)使用React的dangerouslySetInnerHTML屬性,我們可以將HTML內(nèi)容插入到組件中,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10
React 使用recharts實(shí)現(xiàn)散點(diǎn)地圖的示例代碼
這篇文章主要介紹了React 使用recharts實(shí)現(xiàn)散點(diǎn)地圖的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
解決React報(bào)錯(cuò)Rendered more hooks than during
這篇文章主要為大家介紹了React報(bào)錯(cuò)Rendered more hooks than during the previous render解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
React中使用Axios進(jìn)行HTTP請(qǐng)求
這篇文章主要為大家展示了如何在 React 中使用 Axios 進(jìn)行 HTTP 請(qǐng)求,包括 GET 和 POST 請(qǐng)求的使用,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-11-11
React styled-components設(shè)置組件屬性的方法
這篇文章主要介紹了styled-components設(shè)置組件屬性的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08

