Redux与react-redux 【第六章】
redux API
- store.getState() 获取状态
- store.dispatch({type:’increment’,data:value*1}) 添加数据
- store.subscribe() 订阅redux状态的更改 【检测redux的数据变化,变化就掉render, 接收一个回调函数】
简单使用 redux 【精简版】
npm install redux
或者yarn add redux
- 创建一个 sotre.js 引入
import {createStore} from 'redux'
- 创建一个 reducer.js 【本质就是一个函数,接收两个参数:之前的状态【preState,第一次为undefined】,动作对象【action】】【作用:初始化状态和加工状态】
- 引入为组件服务的 reducer
import countReducer from './count_reducer'
- 导出store.js
export default createStore(countReducer)
reducer.js
1
2
3
4
5
6
7
8
9
10
11
12export default function countReducer(preState = 0, action) {
// if(preState === undefined){preState = 0 }
const { type, data } = action
switch (type) {
case 'increment':
return preState + data
case 'decrement':
return preState - data
default:
return preState
}
}store.js
1
2
3
4
5
6
7
8
9
10
11/*
该文件专门用于暴露store对象,整个应用只有一个store对象
*/
// createStore 创建store对象
import {createStore} from 'redux'
// 引入为 Count 组件服务的 reducer
import countReducer from './count_reducer'
export default createStore(countReducer)
// const store = createStore(countReducer)
// export default store入口文件添加 [注意:react-redux 不需要]
1
2
3
4// 检测redux的数据变化,渲染
store.subscribe(() => {
ReactDOM.render(<App />,document.getElementById('root'));
})
简单使用 redux 【完整版】
新增文件:
1.count_action.js 专门用于创建action对象
2.constant.js 放置容易写错的type值
count_action.js
1 | import { INCREMENT, DECREMENT } from './constant' |
求和案例_redux异步action版
(1).明确:延迟的动作不想交给组件自身,想交给action
(2).何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回。
(3).具体编码:
1).yarn add redux-thunk,并配置在store中
2).创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务。
3).异步任务有结果后,分发一个同步的action去真正操作数据。
(4).备注:异步action不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步action。
store.js
1 | import {createStore,applyMiddleware} from 'redux' |
actions.js
1 | //异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。 |
react-redux的基本使用
containers文件下,容器组件
- yarn add react-redux
- import { connect } from ‘react-redux’、引入UI组件、 引入action 对象
- export default connect(mapStateToProps, mapDispatchToProps)(CountUI)
- mapStateToProps:映射状态,返回值是一个对象
- mapDispatchToProps:映射操作状态的方法,返回值是一个对象
- 容器组件中的store是靠props传进去的,而不是在容器组件中直接引入
- 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
31import { connect } from 'react-redux'
// 引入UI组件
import CountUI from '../../components/Count'
// 引入actions 对象
import { incrementAction, decrementAction, incrementAsyncAction } from '../../redux/count_actions'
// 状态
const mapStateToProps = (state) => {
return { count: state }
}
// 操作状态的方法 【方法一:mapDispatchToProps写成函数,返回操作方法】
const mapDispatchToProps = (dispatch,store) => {
return {
jia: (value) => {dispatch(incrementAction(value))},
jian: (value) => {dispatch(decrementAction(value))},
jiaIfOdd: (value) => {
// console.log(store.store.getState());
if(store.store.getState() % 2 !== 0){
dispatch(incrementAction(value))
}
},
jiaAsync: (value,time) => {setTimeout(() => {
dispatch(incrementAsyncAction(value))
}, time)},
}
}
// 【方法二:mapDispatchToProps写成对象,返回操作方法】
export default connect(mapStateToProps, {
jia: incrementAction,
jian: decrementAction,
jiaAsync: incrementAsyncAction,
})(CountUI)
APP组件
- 引入容器组件,删除UI组件
- 引入store,通过props传值给UI组件
优化:让所有需要 store 的容器组件都能获取 store, [Provider组件]
- 在入口文件中index.js,引入
import {Provider} from 'react-redux'
- 引入
import store from './redux/store.js'
ReactDOM.render(<Provider store={store}> <App></App></Provider>,document.getElementById('root'));
- 优化:把UI组件合并到父容器组件里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import React, { Component } from 'react'
// import Count from './components/Count'
// 引入容器组件,删除UI组件
import CountContainer from './containers/Count'
import store from './redux/store.js'
export default class App extends Component {
render() {
return (
<div>
{/* 通过props传值给UI组件 */}
<CountContainer store={store}></CountContainer>
</div>
)
}
}
components文件下,UI组件
- UI组件:不能使用任何redux的api,只负责页面的呈现、交互等
- 容器组件:负责和redux通信,将结果交给UI组件
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
41import React, { Component } from 'react'
export default class Count extends Component {
jia = () => {
const { value } = this.selectValue
this.props.jia(value * 1)
}
jian = () => {
const { value } = this.selectValue
this.props.jian(value * 1)
}
jiaIfOdd = () => {
const { value } = this.selectValue
// 方法一
// this.props.jiaIfOdd(value * 1)
// 方法二
if (this.props.count % 2 !== 0) {
this.props.jia(value * 1)
}
}
jiaAsync = () => {
const { value } = this.selectValue
this.props.jiaAsync(value * 1, 500)
}
render() {
return (
<div>
<h2>当前值为:{this.props.count}</h2>
<select ref={c => this.selectValue = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.jia}>+</button>
<button onClick={this.jian}>-</button>
<button onClick={this.jiaIfOdd}>奇数加</button>
<button onClick={this.jiaAsync}>异步加</button>
</div>
)
}
}
求和案例_react-redux数据共享版
(1).定义一个Pserson组件,和Count组件通过redux共享数据。
(2).为Person组件编写:reducer、action,配置constant常量。
(3).重点:在store.js文件中,Person的reducer和Count的Reducer要使用combineReducers进行合并,
合并后的总状态是一个对象!!!
(4).交给store的是总reducer,最后注意在组件中取出状态的时候,记得“取到位”。
store.js
1 | // combineReducers :整合多个 Reducer |
纯函数
纯函数
- 一类特别的函数: 只要是相同的输入(实参),必定的到相同的输出(返回)
- 约束:
- 不得改写参数数据
- 不会产生任何副作用,例如网络请求、输入和输出设备
- 不能调用 Date.now() 或者 Math.random() 等不纯的方法
- react 的reducer 函数必须是一个纯函数
1
2
3
4
5<!-- name函数不是纯函数 -->
function name(data){
a = data // 不得改写参数数据
}
name(23)
使用开发者工具
- yarn add redux-devtools-extension
- 引入
import { composeWithDevTools } from 'redux-devtools-extension'
export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))
store.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// combineReducers :整合多个 Reducer
import {createStore,applyMiddleware,combineReducers} from 'redux'
import countReducer from './reducers/count_reducer'
import personReducer from './reducers/person_reducer'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
//redux的可视化工具,谷歌的应用商城工具
import { composeWithDevTools } from 'redux-devtools-extension'
// 整合多个 Reducer
const allReducer = combineReducers({
countReducer,
personReducer
})
export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))
其他写法
1 | 第一种写法、 |
求和案例_react-redux最终版
- 所有变量名字要规范,尽量触发对象的简写形式。
- reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer
打包上传到服务器【模拟】
- 下载serve库
npm i serve -g
- serve build 运行,图标变蓝
- npm run build 一般都是打包好后交给后端,后端部署到服务器