React immer與Redux Toolkit使用教程詳解
1. immer
概述:
它和immutable相似的,實現(xiàn)了操作對象的數(shù)據(jù)共享,可以優(yōu)化性能。它實現(xiàn)的原理使用es6的Proxy完成的。小巧,沒有像immutable哪樣有新數(shù)據(jù)類型,而是使用js類型。
安裝:
yarn add immer@9
1.1 setState結(jié)合immer使用
簡單使用:
import React from 'react' // 把源數(shù)據(jù)使用Proxy進(jìn)行代理處理,后面就可以精準(zhǔn)的去找到變化的數(shù)據(jù) import { produce } from 'immer' const state = { count: 1 } // 進(jìn)行代理后,并修改 // draft就是代理對象,它就是state代理對象 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ù)組,對象沒有修改,共享 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 = () => { // 原來的寫法 // this.setState(state => ({ count: state.count + 1 })) // 使用immer來優(yōu)化setState操作 this.setState( produce(draft => { // 不用返回,返加不允許,draft它是一個代理對象,修改后,它能監(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代理的是對象 // 如果它是一個普通值,沒有必要使用immer來完成優(yōu)化操作 let [count, setCount] = useState(100) // 對象類型才是使用immer工作的場景 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中的寫法一樣的,簡化了 // 操作數(shù)據(jù)無需深復(fù)制,提升性能 if ('add' === type) draft.count += payload }, initState) export default createStore(reducer)
前端頁面:
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 新的庫,也是官方推薦今后在項目中使用的 redux 庫,內(nèi)置了immer、redux-thunk和redux-devtools。
安裝:
yarn add @reduxjs/toolkit react-redux
使用:
前臺頁面:
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
redux入口文件:
import { configureStore } from '@reduxjs/toolkit' // 上來它就是分模塊,在項目中,所以的數(shù)據(jù)一定是分模塊來管理的 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配置對象中的key名稱要一致 name: 'count', // 初始化數(shù)據(jù)源 initialState: { num: 10 }, // 修改數(shù)據(jù)源的方法集合 reducers: { // 組件中派發(fā)dispatch(setNum(2)) // 2就會給payload // state它就是proxy對象[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ò)請求 export const fetchUser = createAsyncThunk('user/fetchUser', async page => { // 實現(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個狀態(tài),只取成功狀態(tài) fulfilled // payload中的數(shù)據(jù)就是fetchUser方法它return出來的數(shù)據(jù) builder.addCase(fetchUser.fulfilled, (state, { payload }) => { state.users = payload }) } }) export const { setUsers } = userSlice.actions // 網(wǎng)絡(luò)請求 --- 內(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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React項目中動態(tài)插入HTML內(nèi)容的實現(xiàn)
本文主要介紹了React項目中動態(tài)插入HTML內(nèi)容的實現(xiàn),通過使用React的dangerouslySetInnerHTML屬性,我們可以將HTML內(nèi)容插入到組件中,具有一定的參考價值,感興趣的可以了解一下2023-10-10React 使用recharts實現(xiàn)散點地圖的示例代碼
這篇文章主要介紹了React 使用recharts實現(xiàn)散點地圖的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12解決React報錯Rendered more hooks than during
這篇文章主要為大家介紹了React報錯Rendered more hooks than during the previous render解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12React styled-components設(shè)置組件屬性的方法
這篇文章主要介紹了styled-components設(shè)置組件屬性的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08