React项目状态管理选型
- 全面拥抱typescript,需要对typescript友好。
- 使用简单,不要太复杂,轻量。
- 支持模块化,支持集中管理。
- 使用人数多。
常用redux对比
下载量前三的三个状态管理库
库名 | 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下载量,使用量均排第一,主要原因应该是先发优势,很多其他状态管理器库依赖react-redux,tookit是官方状态管理库,使用量目前最大,并且可以通过指令生成带有tookit状态管理器的项目(npx create-react-app --template redux ,npx create-react-app --template redux-typescript);mobx也是一个非常优秀的react状态管理库,主要优点是使用简单。
常用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();
创建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:仅支持函数组件
- mobx-react:既支持函数组件,也支持函数组件
npm install mobx mobx-react-lite
2、新建store目录,再建counter目录,在该目录下新建counter.store.ts
import { makeAutoObservable } from "mobx";
// 1、定义数据
export class CounterStore {
count: number = 0;
constructor() {
makeAutoObservable(this);
}
increment() {
this.count++;
}
decrement() {
this.count--;
}
}
3、在store根目录,在目录下面新建index.ts统一管理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机制 完成统一方法封装;
// Provider value ={传递的数据}
// 查找机制:useContext 优先从Provider value找 如果找不到 就会手
// createContet方法传递过来的默认参数
const context = React.createContext(rootStore);
// 这个方法作用:通过useContext拿到rootStorre实例对象 然后返回
// 只要在业务组件中 调用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次数的方法
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 方法用于映射状态;
const mapStateToProps = (state: number): { value: number } => ({
value: state
})
// mapDispatchToProps 方法用于映射操作状态的方法
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 优点
- 流程规范,需要按照规范进行开发。
- 函数式编程,在
reducer
中,接受输入,然后输出,不会有副作用发生,幂等性。 - 可追踪性,很容易追踪产生 BUG 的原因。
redux 缺点(tookit已解决)
- 配置 Redux store 过于复杂
- 须添加很多软件包才能开始使用 Redux 做事情
- Redux 有太多样板代码
mobx 优点
- 开发简单,class 中管理 state、action,基于 Proxy 实现的数据响应式。
- 使组件更加颗粒化拆分,并且业务更加容易抽象。
mobx 缺点
- 过于自由,mobx 提供的约定及模版代码很少,如果团队不做一些约定,容易导致团队代码风格不统一。
网友评论