reduex選型

React項目狀態(tài)管理選型

  1. 全面擁抱typescript,需要對typescript友好慕爬。
  2. 使用簡單谢鹊,不要太復雜,輕量。
  3. 支持模塊化,支持集中管理。
  4. 使用人數(shù)多刁愿。

常用redux對比

下載量前三的三個狀態(tài)管理庫

庫名 github start github used 周下載量
React Redux 22.2k 2.1m 5,718,723
redux-toolkit 8.1k 274k 1,664,877
mobx 25.4k 106k 903,357

去年7月份redux-toolkit與mobx下載量情況如下

庫名 github start github used 周下載量
redux-toolkit 5.9k 83.2k 755,564
mobx 23.9k 83.9k 671,787

分析:react-redux下載量,使用量均排第一到逊,主要原因應該是先發(fā)優(yōu)勢铣口,很多其他狀態(tài)管理器庫依賴react-redux滤钱,tookit是官方狀態(tài)管理庫,使用量目前最大脑题,并且可以通過指令生成帶有tookit狀態(tài)管理器的項目(npx create-react-app --template redux 菩暗,npx create-react-app --template redux-typescript);mobx也是一個非常優(yōu)秀的react狀態(tài)管理庫旭蠕,主要優(yōu)點是使用簡單停团。

常用redux基本使用

一、redux-toolkit的基本使用

1掏熬、安裝依賴包
npm install @reduxjs/toolkit react-redux
2佑稠、配置store

在store目錄下新建index.ts文件,代碼如下:

import { configureStore } from '@reduxjs/toolkit'

export const store = configureStore({
  reducer: {},
})

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

修改主頁index.tsx文件如下:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
import { store } from './store/tookit/index';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

// redux-toolkit
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

創(chuàng)建scounterSlice文件旗芬,在store目錄下舌胶,features/counter/counterSlice.ts

import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'

export interface CounterState {
  value: number
}

const initialState: CounterState = {
  value: 0,
}

export const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      // Redux Toolkit allows us to write "mutating" logic in reducers. It
      // doesn't actually mutate the state because it uses the Immer library,
      // which detects changes to a "draft state" and produces a brand new
      // immutable state based off those changes
      state.value += 1
    },
    decrement: (state) => {
      state.value -= 1
    },
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload
    },
  },
})

// Action creators are generated for each case reducer function
export const { increment, decrement, incrementByAmount } = counterSlice.actions

export default counterSlice.reducer

修改store/toolkit目錄下index.ts

import counterReducer from "./features/counter/counterSlice";


export const store = configureStore({
    reducer: {
        counter: counterReducer
    }
});
3、新建Counter組件

目錄:src/conponent/Counter.tsx

import React, { Component } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { decrement, increment, incrementByAmount } from '../store/tookit/features/counter/counterSlice';
import type { RootState } from '../store/tookit/index';
import './counter.css';

type Props = {}

function Counter({ }: Props) {
    const count = useSelector((state: RootState) => state.counter.value);
    const dispatch = useDispatch();
    return (
        <div>
            <div>{count}</div>
            <div className='button'>
                <button onClick={() => dispatch(increment())}>+</button>
                <button onClick={() => dispatch(decrement())}>-</button>
                <button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
            </div>
        </div>
    )
}

export default Counter
4疮丛、在App.tsx引入Counter組件
import React from 'react';
import './App.css';
import Counter from './components/Counter';

function App() {
  
  return (
    <div className="App">
      <Counter />
    </div>
  );
}

export default App;
5幔嫂、異步操作
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import type { PayloadAction } from '@reduxjs/toolkit'

export interface CounterState {
    value: number
}

const initialState: CounterState = {
    value: 0
};

export const counterSlice = createSlice({
    name: 'counter',
    initialState,
    reducers: {
        increment: (state) => {
            state.value += 1;
        },
        decrement: (state) => {
            state.value -= 1;
        },
        incrementByAmount: (state, action: PayloadAction<number>) => {
            state.value += action.payload;
        }
    }, 
    extraReducers(builder) {
        builder.addCase(incrementAsync.fulfilled, (state, { payload }) => {
            state.value += payload;
        })
    }
});

export const incrementAsync = createAsyncThunk<number>(
    'incrementAsync',
    async (): Promise<number> => {
        const res: any = await new Promise<number>(r => {
            setTimeout(() => {
                r(2);
            }, 2000);
            
        });
        return res;
    }
)

export const { increment, decrement, incrementByAmount } = counterSlice.actions

export default counterSlice.reducer
// import React, { Component } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { decrement, increment, incrementByAmount, incrementAsync } from '../store/tookit/features/counter/counterSlice';
import type { AppDispatch, RootState } from '../store/tookit/index';
import './counter.css';

// type Props = {}

function Counter() {
    const count = useSelector((state: RootState) => state.counter.value);
    const dispatch: AppDispatch = useDispatch();
    
    return (
        <div>
            <div>{count}</div>
            <div className='button'>
                <button onClick={() => dispatch(increment())}>+</button>
                <button onClick={() => dispatch(decrement())}>-</button>
                <button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
                <button onClick={() => dispatch(incrementAsync())}>+2</button>
            </div>
        </div>
    )
}

export default Counter

二、mobx基本使用

1誊薄、安裝mobx依賴包
  • mobx:核心庫
  • mobx-react-lite:僅支持函數(shù)組件
  • mobx-react:既支持函數(shù)組件履恩,也支持函數(shù)組件
npm install mobx mobx-react-lite
2、新建store目錄呢蔫,再建counter目錄切心,在該目錄下新建counter.store.ts
import { makeAutoObservable } from "mobx";

// 1、定義數(shù)據(jù)
export class CounterStore {
    count: number = 0;
    constructor() {
        makeAutoObservable(this);
    }

    increment() {
        this.count++;
    }

    decrement() {
        this.count--;
    }
}
3片吊、在store根目錄绽昏,在目錄下面新建index.ts統(tǒng)一管理store
import { CounterStore } from './counter/counter.store';
import React from 'react';

class RootStore {
    public counterStore: any;
    constructor() {
        this.counterStore = new CounterStore();
    }
}

// 實例化操作
const rootStore = new RootStore();
// 使用react context機制 完成統(tǒng)一方法封裝;
// Provider value ={傳遞的數(shù)據(jù)}
// 查找機制:useContext 優(yōu)先從Provider value找 如果找不到 就會手
// createContet方法傳遞過來的默認參數(shù)
const context = React.createContext(rootStore);
// 這個方法作用:通過useContext拿到rootStorre實例對象  然后返回
// 只要在業(yè)務組件中 調(diào)用useStore() -> rootStore
const useStore = () => React.useContext(context);

export { useStore };
4俏脊、使用store

新建MobxCounter.tsx組件全谤,代碼如下

import { observer } from 'mobx-react-lite';
import React from 'react'
import './counter.css';
import { useStore } from '../store/mobx/index';

type Props = {}

function MobxCounter({ }: Props) {
    const { counterStore } = useStore();
    return (
        <div>
            <div>{counterStore.count}</div>
            <div className='button'>
                <button onClick={() => counterStore.increment()}>+</button>
                <button onClick={() => counterStore.decrement()}>-</button>
            </div>
        </div>
    )
}
// 使用observer是關鍵
export default observer(MobxCounter)

三、redux-react基本使用

1爷贫、安裝依賴
npm i redux react-redux @types/react-redux
2认然、新建常量文件store/redux/contant/index.ts,代碼如下:
export const ADD = 'ADD';
export type ADD = typeof ADD;

export const LESSEN = 'LESSEN';
export type LESSEN = typeof LESSEN;
3沸久、新建action文件store/redux/actions/index.ts季眷,代碼:
import { ADD, LESSEN } from "../constants";

export interface ADDAction {
    type: ADD
}

export interface LESSENAction {
    type: LESSEN
}

export type ModifyAction = ADDAction | LESSENAction;

// 增加state次數(shù)的方法
export const add = ():ADDAction => ({
    type: ADD
})
export const lessen = ():LESSENAction => ({
    type: LESSEN
})
4、新建counter.reducer.ts文件
import { ModifyAction } from '../actions/index';
import { ADD, LESSEN } from '../constants/index';

export const counterReducer = (state = 0, action: ModifyAction) => {
    switch (action.type) {
        case ADD:
            return state + 1;
        case LESSEN:
            return state - 1;
        default:
            return state;
    }
}
5卷胯、在store/redux目錄下面新建index.ts文件,用于集中管理reducer
import { createStore } from "redux";
import { rootReducer } from './reducers/index';

const store = createStore(rootReducer);

export default store;
6威酒、新建ReduxCounter.tsx組件
import React from 'react'
import './counter.css';
import { connect } from 'react-redux'
import { Dispatch } from 'redux'
import { add, lessen } from '../store/redux/actions/index';

type Props = {
    // value: number,
    // onIncrement: () => void,
    // onDecrement: () => void
}

function ReduxCounter(props: any) {
    const { value, onadd, onlesen } = props;
    return (
        <div>
            <div>{value.counter}</div>
            <div className='button'>
                <button onClick={() => onadd()}>+</button>
                <button onClick={() => onlesen()}>-</button>
            </div>
        </div>
    )
}
// mapStateToprops 方法用于映射狀態(tài)窑睁;
const mapStateToProps = (state: number): { value: number } => ({
    value: state
})
// mapDispatchToProps 方法用于映射操作狀態(tài)的方法
const mapDispatchToProps = (dispatch: Dispatch) => ({
    onadd: () => dispatch(add()),
    onlesen: () => dispatch(lessen())
})

export default connect(mapStateToProps, mapDispatchToProps)(ReduxCounter)
7挺峡、在主入口index.tsx添加Provider
import { Provider } from 'react-redux'
import store from './store/redux/index';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

// redux-toolkit redux
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

常用redux總結

redux/toolkit 優(yōu)點

  1. 流程規(guī)范,需要按照規(guī)范進行開發(fā)担钮。
  2. 函數(shù)式編程橱赠,在 reducer 中,接受輸入箫津,然后輸出狭姨,不會有副作用發(fā)生,冪等性苏遥。
  3. 可追蹤性饼拍,很容易追蹤產(chǎn)生 BUG 的原因。

redux 缺點(tookit已解決)

  1. 配置 Redux store 過于復雜
  2. 須添加很多軟件包才能開始使用 Redux 做事情
  3. Redux 有太多樣板代碼

mobx 優(yōu)點

  1. 開發(fā)簡單田炭,class 中管理 state师抄、action,基于 Proxy 實現(xiàn)的數(shù)據(jù)響應式教硫。
  2. 使組件更加顆吝端保化拆分,并且業(yè)務更加容易抽象瞬矩。

mobx 缺點

  1. 過于自由茶鉴,mobx 提供的約定及模版代碼很少,如果團隊不做一些約定景用,容易導致團隊代碼風格不統(tǒng)一蛤铜。
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市丛肢,隨后出現(xiàn)的幾起案子围肥,更是在濱河造成了極大的恐慌,老刑警劉巖蜂怎,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件穆刻,死亡現(xiàn)場離奇詭異,居然都是意外死亡杠步,警方通過查閱死者的電腦和手機氢伟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來幽歼,“玉大人朵锣,你說我怎么就攤上這事〉樗剑” “怎么了诚些?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我诬烹,道長砸烦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任绞吁,我火速辦了婚禮幢痘,結果婚禮上,老公的妹妹穿的比我還像新娘家破。我一直安慰自己颜说,他們只是感情好,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布汰聋。 她就那樣靜靜地躺著门粪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪马僻。 梳的紋絲不亂的頭發(fā)上庄拇,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機與錄音韭邓,去河邊找鬼措近。 笑死,一個胖子當著我的面吹牛女淑,可吹牛的內(nèi)容都是我干的瞭郑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鸭你,長吁一口氣:“原來是場噩夢啊……” “哼屈张!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起袱巨,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤阁谆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后愉老,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體场绿,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年嫉入,在試婚紗的時候發(fā)現(xiàn)自己被綠了焰盗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡咒林,死狀恐怖熬拒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情垫竞,我是刑警寧澤澎粟,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響捌议,放射性物質(zhì)發(fā)生泄漏哼拔。R本人自食惡果不足惜引有,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一瓣颅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧譬正,春花似錦宫补、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抒巢,卻和暖如春贫贝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蛉谜。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工稚晚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人型诚。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓客燕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親狰贯。 傳聞我的和親對象是個殘疾皇子也搓,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容