【笔记】React通过Redux实现状态管理

前言

React通过reduxjs/redux实现状态管理

下载依赖

1
npm install redux

定义Store

定义Action常量

src/store/constants.js
1
export const CHANGE_KEY = "changeKey";

定义Reducer

src/store/reducer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import * as actionTypes from "./constants";

const initialState = {
key: "default"
};

function reducer(state = initialState, action) {
switch (action.type) {
case actionTypes.CHANGE_KEY:
const objCopy = Object.assign({}, state, {});
objCopy.key = action.payload;
return objCopy;
default:
return state;
}
}

export default reducer;

创建Store

src/store/index.js
1
2
3
4
5
6
import { createStore } from "redux";
import reducer from "./reducer";

const store = createStore(reducer);

export default store;

获取数据

src/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import React from "react";
import store from "./store/index.js";

export class Component extends React.Component {
constructor() {
super();

this.state = {
key: store.getState().key
};
}

componentDidMount() {
store.subscribe(() => {
this.setState({ key: store.getState().key });
});
}

componentWillUnmount() {
store.unsubscribe();
}

render() {
return (
<>
{ this.state.key }
</>
);
}
}

修改数据

定义Action对象

src/store/actionCreator.js
1
2
3
4
5
6
import * as actionTypes from "./constants";

export const changeKey = (payload) => ({
type: actionTypes.CHANGE_KEY,
payload
});

派发事件

src/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import React from "react";
import store from "./store/index.js";
import { changeKey } from "./store/actionCreator";

export class Component extends React.Component {
constructor() {
super();

this.fn = this.fn.bind(this);
}

fn() {
store.dispatch(changeKey("value"));
}

render() {
return (
<>
<button onClick={ this.fn }></button>
</>
);
}
}

通过react-redux实现自动映射

  • 通过react-redux实现自动映射Redux的state到组件的props

下载依赖

1
npm install react-redux

通过Provider组件包裹根组件

src/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from "react";
import ReactDOM from "react-dom";
import App from "./App.jsx";
import { Provider } from "react-redux";
import store from "./store/index.js";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Provider store={ store }>
<App />
</Provider>
</React.StrictMode>
);

获取数据

  • 通过mapStateToProps()的第个参数,映射Redux的state到props
src/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from "react";
import { connect } from "react-redux";

class Component extends React.Component {
constructor() {
super();
}

render() {
return (
<>
{ this.props.key }
</>
);
}
}

const mapStateToProps = (state) => ({
key: state.key
});

export default connect(mapStateToProps)(Component);

修改数据

  • 通过mapStateToProps()的第个参数,映射Redux的dispatch到props

定义Action对象

src/store/actionCreator.js
1
2
3
4
5
6
import * as actionTypes from "./constants";

export const changeKey = (payload) => ({
type: actionTypes.CHANGE_KEY,
payload
});

派发事件

src/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import React from "react";
import { connect } from "react-redux";
import { changeKey } from "./store/actionCreator";

class Component extends React.Component {
constructor() {
super();

this.fn = this.fn.bind(this);
}

fn() {
store.dispatch(changeKey("value"));
}

render() {
return (
<>
<button onClick={ this.fn }></button>
</>
);
}
}

const mapDispatchToProps = (dispatch) => ({
changeKey: (payload) => dispatch(changeKey(payload));
})

export default connect(null, mapDispatchToProps)(Component);

通过react-thunk实现异步操作

  • 默认dispatch()方法只能传递对象作为参数
  • 通过react-thunk实现dispatch()方法传递函数作为参数

下载依赖

1
npm install react-thunk axios

应用中间件

src/store/index.js
1
2
3
4
5
6
7
import { createStore } from "redux";
import reducer from "./reducer";
import thunk from "react-thunk";

const store = createStore(reducer, applyMiddleware(thunk));

export default store;

修改数据

定义Action函数

src/store/actionCreator.js
1
2
3
4
5
6
7
8
9
10
import * as actionTypes from "./constants";
import axios from "axios";

export const changeKey = (payload) => {
return (dispatch, getState) => {
axios.get("https://example.com").then(res => {
dispatch(changeKey(res.data));
});
}
};

派发事件

src/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import React from "react";
import { connect } from "react-redux";
import { changeKey } from "./store/actionCreator";

class Component extends React.Component {
constructor() {
super();

this.fn = this.fn.bind(this);
}

fn() {
store.dispatch(changeKey("value"));
}

render() {
return (
<>
<button onClick={ this.fn }></button>
</>
);
}
}

const mapDispatchToProps = (dispatch) => ({
changeKey: (payload) => dispatch(changeKey(payload));
})

export default connect(null, mapDispatchToProps)(Component);

拆分模块

定义Store

分模块定义Action常量

src/store/constants-1.js
1
export const REDUCER1_CHANGE_KEY = "reducer1ChangeKey";
src/store/constants-2.js
1
export const REDUCER2_CHANGE_KEY = "reducer2ChangeKey";

分模块定义Reducer

src/store/reducer-1.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import * as actionTypes from "./constants-1";

const initialState = {
key: "default"
};

function reducer(state = initialState, action) {
switch (action.type) {
case actionTypes.REDUCER1_CHANGE_KEY:
const objCopy = Object.assign({}, state, {});
objCopy.key = action.payload;
return objCopy;
default:
return state;
}
}

export default reducer;
src/store/reducer-2.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import * as actionTypes from "./constants-2";

const initialState = {
key: "default"
};

function reducer(state = initialState, action) {
switch (action.type) {
case actionTypes.REDUCER2_CHANGE_KEY:
const objCopy = Object.assign({}, state, {});
objCopy.key = action.payload;
return objCopy;
default:
return state;
}
}

export default reducer;

创建Store

  • 通过combineReducers()合并多个Reducer
src/store/index.js
1
2
3
4
5
6
7
8
9
10
11
12
import { createStore, combineReducers } from "redux";
import reducer1 from "./reducer-1";
import reducer2 from "./reducer-2";

const reducer = combineReducers({
reducer1: reducer1,
reducer2: reducer2
});

const store = createStore(reducer);

export default store;

获取指定模块的数据

src/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import React from "react";
import store from "./store/index.js";

export class Component extends React.Component {
constructor() {
super();

this.state = {
key: store.getState().reducer1.key
};
}

componentDidMount() {
store.subscribe(() => {
this.setState({ key: store.getState().reducer1.key });
});
}

componentWillUnmount() {
store.unsubscribe();
}

render() {
return (
<>
{ this.state.key }
</>
);
}
}

修改指定模块的数据

定义Action对象

src/store/actionCreator.js
1
2
3
4
5
6
import * as actionTypes from "./constants";

export const reducer1ChangeKey = (payload) => ({
type: actionTypes.REDUCER1_CHANGE_KEY,
payload
});

派发事件

src/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import React from "react";
import store from "./store/index.js";
import { reducer1ChangeKey } from "./store/actionCreator";

export class Component extends React.Component {
constructor() {
super();

this.fn = this.fn.bind(this);
}

fn() {
store.dispatch(reducer1ChangeKey("value"));
}

render() {
return (
<>
<button onClick={ this.fn }></button>
</>
);
}
}

通过ReduxToolkit实现拆分模块和异步操作

下载依赖

1
npm install @reduxjs/toolkit axios

定义Store

分模块定义Reducer

src/store/reducer-1.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { createSlice } from "@reduxjs/toolkit";

const reducerSlice = createSlice({
name: "reducer1",
initialState: {
key: "default"
},
reducers: {
reducer1ChangeKey: (state, action) => {
state.key = action.payload;
}
}
});

export const { reducer1ChangeKey } = reducerSlice.actions;

export default reducerSlice.reducer;
src/store/reducer-2.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { createSlice } from "@reduxjs/toolkit";

const reducerSlice = createSlice({
name: "reducer2",
initialState: {
key: "default"
},
reducers: {
reducer2ChangeKey: (state, action) => {
state.key = action.payload;
}
}
});

export const { reducer2ChangeKey } = reducerSlice.actions;

export default reducerSlice.reducer;

创建Store

src/store/index.js
1
2
3
4
5
6
7
8
9
10
11
12
import { configureStore } from "@reduxjs/toolkit";
import reducer1 from "./reducer-1";
import reducer2 from "./reducer-2";

const store = configureStore({
reducer: {
reducer1: reducer1,
reducer2: reducer2
},
});

export default store;

获取指定模块的数据

src/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import React from "react";
import store from "./store/index.js";

export class Component extends React.Component {
constructor() {
super();

this.state = {
key: store.getState().reducer1.key
};
}

componentDidMount() {
store.subscribe(() => {
this.setState({ key: store.getState().reducer1.key });
});
}

componentWillUnmount() {
store.unsubscribe();
}

render() {
return (
<>
{ this.state.key }
</>
);
}
}

修改指定模块的数据

src/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import React from "react";
import store from "./store/index.js";
import { reducer1ChangeKey } from "./store/reducer-1";

export class Component extends React.Component {
constructor() {
super();

this.fn = this.fn.bind(this);
}

fn() {
store.dispatch(reducer1ChangeKey("value"));
}

render() {
return (
<>
<button onClick={ this.fn }></button>
</>
);
}
}

异步操作

直接通过派发事件修改数据

src/store/reducer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";

createAsyncThunk("fetchData", async (extraData, store) => {
const res = await axios.get("https://example.com");
store.dispatch(reducerChangeKey(res.data));
});

const reducerSlice = createSlice({
name: "reducer",
initialState: {
key: "default"
},
reducers: {
reducerChangeKey: (state, action) => {
state.key = action.payload;
}
}
});

export default reducerSlice.reducer;

通过计算属性名监听异步操作状态

src/store/reducer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";

const fetchData = createAsyncThunk("fetchData", async (extraData, store) => {
const res = await axios.get("https://example.com");
return res.data;
});

const reducerSlice = createSlice({
name: "reducer",
initialState: {
key: "default"
},
extraReducers: {
[fetchData.padding]: (state, action) => {
...
},
[fetchData.fulfilled]: (state, action) => {
state.key = action.payload;
},
[fetchData.rejected]: (state, action) => {
...
}
}
});

export default reducerSlice.reducer;

通过链式调用监听异步操作状态

src/store/reducer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";

const fetchData = createAsyncThunk("fetchData", async (extraData, store) => {
const res = await axios.get("https://example.com");
return res.data;
});

const reducerSlice = createSlice({
name: "reducer",
initialState: {
key: "default"
},
extraReducers: (builder) => {
builder.addCase(fetchData.padding, (state, action) => {
...
}).addCase(fetchData.fulfilled, (state, action) => {
state.key = action.payload;
}).addCase(fetchData.rejected, (state, action) => {
...
});
}
});

export default reducerSlice.reducer;

完成