前言

上两月忙其他的事情,由此学习的步伐暂停了近两个月的时间,现在终于有时间继续啦!之前在学习 redux 的过程中没有整理笔记,继续开始的时候发现知识点居然忘记了好多,还是老话说的好:“好记性不如烂笔头!”;写成一篇文章一是对自己学习过程的记录,也是对知识点的总结,最终目的是为了让知识点掌握的更加牢固~

安装依赖

提供了两个 api

  1. Provider 为后代组件提供 store
  2. connect 为组件提供数据和变更方法
1
yarn add react-redux

API

Provider

<Provider store> 使组件层级中的 connect() 方法能够获得 Redux store。正常情况下,根组件应该嵌套在 <Provider> 中才能使用 connect() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import './index.css'
import App from './App'

import store from './store/'

// 把Provider放在根组件外层,使子组件能获得store
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)

connect

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
连接 React 组件与 Redux store, 返回一个新的已与 Redux store 连接的组件类。

  • mapStateToProps
  • mapDispatchToProps
  • mergeProps
    如果指定了这个参数, mapStateToProps()mapDispatchToProps() 的执行结果和组件自身的 props 将传入到这个回调函数中。该回调函数返回的对象将作为 props 传递到被包装的组件中。你也许可以用这个回调函数,根据组件的 props 来筛选部分的 state 数据,或者把 props 中 的某个特定变量与 action creator 绑定在一起。如果你省略这个参数,默认情况下返回Object.assign({}, ownProps, stateProps, dispatchProps) 的结果。

react-redux 使用 类组件

store/index

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 { createStore, applyMiddleware, combineReducers } from 'redux'
import thunk from 'redux-thunk' // 异步
import logger from 'redux-logger' // logger
import promise from 'redux-promise' // 处理promise

function countReducer(state = 0, action) {
switch (action.type) {
case 'ADD':
return state + (action.payload || 1)
case 'MINUS':
return state - (action.payload || 1)
default:
return state
}
}

// 创建一个数据仓库 combineReducers组合reducer applyMiddleware扩展redux的中间件
const store = createStore(
combineReducers({ count: countReducer }),
applyMiddleware(thunk, promise, logger)
)

// 导出的store在 index.js 中通过<Provider store></Provider>组件传入<App/>根组件
export default store

pages/reactReduxPage

通过 connect 的mapStateToProps映射statemapDispatchToProps映射dispatch到组件的props身上;
mapDispatchToProps 可以是对象形式,也可以是函数形式:
对象:组件 props 身上就会有具体的 dispatch 方法;
函数:组件身上会有具体的方法,还有 redux 的 dispatch 方法,redux 提供了 bindActionCreators帮助我们写mapDispatchToProps

注意:mapStateToPropsmapDispatchToProps的第二个参数都是ownProps,慎用!

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
@connect(
({ count }) => ({ count }),
// mapDispatchToProps

// 1. 对象 可以通过 this.props.add() this.props.minus()调用
// {
// add: () => ({ type: 'ADD' }),
// minus: () => ({ type: 'MINUS' })
// },

// 2. 函数 将dispatch也扩展进去
// dispatch => {
// const add = () => dispatch({type: "ADD"});
// const minus =() => dispatch({type: "MINUS"});
// return { dispatch, add, minus };
// },

// 3. 函数 如果方法太多的话,一个一个导出会很麻烦,由此redux提供了bindActionCreators帮我们组合dispatch和action
(dispatch) => {
// 创建一个对象
let creators = {
add: () => ({ type: 'ADD' }),
minus: () => ({ type: 'MINUS' }),
}

creators = bindActionCreators(creators, dispatch)
// 直接返回 creators
return { dispatch, ...creators }
}
)
class ReactReduxPage extends React.Component {
render() {
// console.log("props", this.props); //sy-log
const { count, dispatch, add, minus } = this.props

return (
<div>
<h1>ReactReduxPage</h1>
<p>{count}</p>
<button onClick={add}>ADD</button>
<button onClick={minus}>MINUS</button>
<button
onClick={() => {
dispatch({ type: 'ADD' })
}}
>
dispatch
</button>
</div>
)
}
}

写装饰器的话,@connet 里面看起来会比较乱,一般在写项目的时候都会把mapStateToPropsmapDispatchToProps写到组件的下边:

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
import React from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

class ReactReduxPage extends React.Component {
render() {
// console.log("props", this.props); //sy-log
const { count, dispatch, add, minus } = this.props

return (
<div>
<h1>ReactReduxPage</h1>
<p>{count}</p>
<button onClick={add}>ADD</button>
<button onClick={minus}>MINUS</button>
<button
onClick={() => {
dispatch({ type: 'ADD' })
}}
>
dispatch
</button>
</div>
)
}
}

// mapStateToProps Fucntion
// !慎重定义ownProps,因为你一旦定义ownProps,那么每当ownProps发生改变的时候,当前的 mapStateToProps都会被调用,
const mapStateToProps = ({ count }) => ({ count })

// Fucntion 参数是dispatch与ownProps
// !慎重定义ownProps,因为你一旦定义ownProps,那么每当ownProps发生改变的时候,当前的mapStateToProps都会被调用,容易影响性能
const mapDispatchToProps = (dispatch) => {
let creators = {
add: () => ({ type: 'ADD' }),
minus: () => ({ type: 'MINUS' }),
}
creators = bindActionCreators(creators, dispatch)
return { dispatch, ...creators }
}

export default connect(mapStateToProps, mapDispatchToProps)(ReactReduxPage)

react-redux 使用 函数组件

store 的注入根组件等方法和上面的类组件都是一样的,区别就在组件内部使用 store 数据的区别,hook 的方法会更加的简洁和方便;
主要是利用react-redux提供的 useSelecteruseDispatch两个 hook;

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
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'

const ReactReduxHookPage = () => {
// 类似于 mapStateToProps
const count = useSelector(({ count }) => count)
const dispatch = useDispatch()

const add = () => {
dispatch({ type: 'ADD' })
}

const minus = () => {
dispatch({ type: 'MINUS' })
}

return (
<div>
<h1>ReactReduxHookPage</h1>
<p>{count}</p>
<button onClick={add}>ADD</button>
<button onClick={minus}>MINUS</button>
<button onClick={() => {dispatch({ type: 'ADD' })}}>dispatch</button>
</div>
)
}

export default ReactReduxHookPage

总结

以上记录了react-redux的基本使用,尚未涉及处理异步情况,处理异步问题计划另起一篇文章去详细讲述。
很多人在学习react的时候感觉很难,我猜大部分就是对这个react-redux拎不清,其实使用方法都很简单,主要就是react、react-redux写法都很自由,一但项目大起来,如何优雅的去编写项目代码保证项目具有良好的扩展性、阅读性、以及代码的健壮性,确实是一个需要重要关注的点。