React-Redux

React-Redux

npm安装

1
npm i redux react-redux @reduxjs/toolkit

Redux基本概念

redux将所有数据存储到树中,且树是唯一的。

1
2
3
4
5
store:存储树结构。
state:维护的数据,一般维护成树的结构。
reducer:对state进行更新的函数,每个state绑定一个reducer。传入两个参数:当前state和action,返回新state
action:一个普通字典,存储reducer的传入参数,一般描述对state的更新类型。
dispatch:传入一个参数action,对整棵state树操作一遍。

React-Redux基本概念

1
2
3
4
Provider组件:用来包裹整个项目,其store属性用来存储redux的store对象。
connect(mapStateToProps, mapDispatchToProps)函数:用来将store与组件关联起来。
mapStateToProps:每次store中的状态更新后调用一次,用来更新组件中的值。
mapDispatchToProps:组件创建时调用一次,用来将store的dispatch函数传入组件。

构建React-Redux

首先在项目文件下构建下图红框所示文件

store.js文件含义及代码:

store.js 用来存储所有的state,该文件将所有的state存储为一个树形结构,而每个state 都有 一个绑定的reducer来对数据state进行维护,所以我们将 statereducer 的内容统一放到 reducer.js

1
2
3
4
5
6
7
8
9
import { configureStore } from "@reduxjs/toolkit"
import reducer from './reducer'; // 引入reducer,将其整合为一个树

// configureStore将多个state转为一个store存储树结构
const store = configureStore({
reducer: reducer,
});

export default store;
actions.js文件含义及代码:

actions 就只是一个普通的字典,存储所有可能对 state 进行的操作的操作名称,在对 state 进行操作时,会将 actions 的对应操作的名称传给 reducerreducer 根据不同的操作名,对 state 进行相应的更新

1
2
3
4
5
6
7
const ACTIONS = {
Add: "add", // 对数字加法操作
Sub: "sub", // 对数字减法操作
Concat: "concat", // 对字符串连接操作
}

export default ACTIONS;
reducer.js文件含义及代码:

reducer 是真正对 state 进行数据操作的部分,它被 store 连着 state 整合为了树结构,它接收 actions 的操作名来对 state 进行数据更新

reducer 是一个函数,任何一个组件,如果需要对 state 进行操作,则可使用 mapDispatchToProps

任何一个组件,如果需要使用 state 中的值并且根据 state 的值动态改变,则可使用 mapDispatchToProps

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 ACTIONS from "./actions";

// reducer是一个函数
const reducer = (state = {
// state中的number和string是全部的数据
number: 0,
string: "",
}, action) => {
// action.type 由用户构建mapDispatchToProps时自己定义,但要在actions.js找得到对应的操作
switch (action.type) {
case ACTIONS.Add: // 如果mapDispatchToProps中传入的操作名,是actions对应的操作,则执行
let add_new_state = {
...state,
// mapDispatchToProps的return是一个字典,action.value是自己定义的key
// 通过这个key让对state更新的操作更加灵活,相当于一个参数
number: state.number + action.value
}
return add_new_state;
case ACTIONS.Concat:
let concat_new_state = {
...state,
string: state.string + action.value
}
return concat_new_state;
default:
return state;
}
};

export default reducer;

用React-Redux时,需添加Provider

index.js 中,需要加入 <Provider></Provider>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/js/bootstrap';

import { Provider } from 'react-redux';
import App from './components/app';
import store from './redux/store';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
{/* 用React-Redux时,需添加Provider */}
<Provider store={store}>
<App></App>
</Provider>
</React.StrictMode>
);

在各组件中 “使用” 和 “更新” state

构建两个组件 string.jsxnumber.jsx

app.jsx 中引用这两个组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, { Component } from 'react';
import Number from './content/number';
import String from './content/string';

class App extends Component {
state = { }
render() {
return (
<React.Fragment>
<Number></Number>
<hr />
<String></String>
</React.Fragment>
);
}
}

export default App;
number.jsx

number.jsx 中,我们要用一个按钮,对 state 中的数字进行每次加10的操作,并将通过 state.number,实时将更新操作进行显示。

重点关注 connectmapStateToPropsmapDispatchToProps 这三个点

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import React, { Component } from 'react';

// connect函数用来将store与组件关联起来
import {connect} from 'react-redux';

// 引入ACTIONS
import ACTIONS from './../../redux/actions';

class Number extends Component {
state = { }
render() {
return (
<React.Fragment>
<h3>state中number的值: {this.props.number}</h3>
<button style={{marginLeft: 50}} onClick={this.handleClickAdd}>加10</button>
</React.Fragment>
);
}

handleClickAdd = () => {
this.props.add(10);
}
}

// 获取state中的数据,之后在Number类组件中,通过this.props.number使用
let mapStateToProps = (state, props) => {
return {
number: state.number,
}
}

// 对state数据进行操作,之后在Number类组件中,通过 this.props.add(i)来使用
let mapDispatchToProps = {
// 这个add名字随便取(但建议与ACTIONS字典中的value一致),只是在Number类组件中使用该函数
add: (i) => {
return {
type: ACTIONS.Add,
value: i,
}
},
}

// mapStateToProps:
// 将number绑定到this.props
// 这样就可以在Number类组件中使用这个state.number

// mapDispatchToProps:
// 这样就可以在类组件中修改state.number
export default connect(mapStateToProps, mapDispatchToProps)(Number);
string.jsx

string.jsx 中的操作与 number.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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import React, { Component } from 'react';
import ACTIONS from '../../redux/actions';
import {connect} from 'react-redux';

class String extends Component {
state = { }
render() {
return (
<React.Fragment>
<h3>String: {this.props.string}</h3>
<button
style={{marginLeft: 50}}
onClick={() => {this.handleClicConcat("A")}}
>
字母A
</button>

<button
style={{marginLeft: 50}}
onClick={() => {this.handleClicConcat("B")}}
>
字母B
</button>

<button
style={{marginLeft: 50}}
onClick={() => {this.handleClicConcat("C")}}
>
字母C
</button>
</React.Fragment>
);
}

handleClicConcat = (s) => {
this.props.concat(s);
}
}

let mapStateToProps = (state, props) => {
return {
string: state.string,
}
}

let mapDispatchToProps = {
concat: (s) => {
return {
type: ACTIONS.Concat,
value: s,
}
},
}

export default connect(mapStateToProps, mapDispatchToProps)(String);

本博客所有文章除特别声明外,转载请注明出处!