目前使用版本
"redux": "^4.0.5"
"react-redux": "^7.2.0",
建议先了解 Redux 的使用!Redux使用(纯Redux使用)
React-Redux 是 Redux 和 React 的绑定库!
为什么要使用这个 React-Redux 库:
在之前的文章Redux使用(纯Redux使用)里面使用的是 store.subscribe()
的方式进行监听了store
的里面的state
的变化!虽说这样做也可以,但是会有其他的性能问题,比如:渲染页面重复的问题,你可能通过生命周期函数shouldComponentUpdate
可以处理,但是这样太繁琐,特别是组件越来越复杂之后!
React-Redux 这个库在官方说明中是有性能优化的!特别是提供了一种connect()
方式来进行包装组件,这种方式就是我们在做 容器化组件 和 展示组件 进行 分离的时候的 容器化组件 !
- 容器组件:处理 props 或者 state
- 展示组件:只负责展示界面
比如说:你把网路请求放到 容器组件 中,然后在 容器组件 里面把数据组装好,然后传递给 展示组件 直接渲染页面展示!
可以看看我之前的文章:React高阶组件
核心API
- <Provider store={store}>...</Provider>:这个组件是重点,要在你的根目录下的index.js文件把根组件进行包裹
import TodoList from './list/TodoList';
import { Provider } from 'react-redux'
import store from './redux/store/index'
========================= 省略一大波代码 ======
// 重点这里
<Provider store={store}>
<TodoList />
</Provider>,
-
connect(....) :连接函数,把组件和redux进行关联!这个是重点函数,这里可以把
state
和dispatch
传递进去!
connect(....) 有几个参数很关键(重点关注两个):
-
mapStateToProps(state, [ownProps]):如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要
Redux store
发生改变,mapStateToProps
函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并!
这个函数,就是监听 Redux store 的数据变化的!!
/**
* 把 store 里面 state 状态,附加到 props 上
* 这里的参数两个参数,connect()自动赋值
* @param {*} state store的全局状态,connect()自动赋值
* @param {*} ownProps 组件本身自己带的props, connect()自动赋值
*/
const mapStateToProps = (state, ownProps) => {
/**
* 这里可以只拿取你需要的 state 里面的数据,这样可以节省性能开销
* 比如我这里只要 state 里面的 list
* 然后组件里面可以通过 props 获取 list 的值
*/
return { list: state.list }
}
-
mapDispatchToProps(dispatch, [ownProps]):如果传递的是一个对象,那么每个定义在该对象的函数都将被当作
Redux action creator
,对象所定义的方法名将作为属性名;每个方法将返回一个新的函数,函数中dispatch
方法会将action creator
的返回值作为参数执行。这些属性会被合并到组件的props
中。
(1):这个函数,就是用来执行
dispatch
的,就是说可以把这个组件中所有的dispatch
操作从组件里面都提取出来统一管理!
(2):如果不定义mapDispatchToProps
,那么默认把所有的dispatch
都传递到组件中,那么你可以在组件中直接操作dispatch
/**
* 把里面定义的函数附加到 props 上
* 组件可以通过 props.onTodoClick(id) 进行调用
*/
const mapDispatchToProps = (dispatch, ownProps) => {
return {
/**
* 可以定义多个函数
* 组件可以通过 props.onTodoClick(id) 进行调用
**/
onTodoClick: id => {
dispatch(toggleTodo(id))
}
}
}
开始使用 React-Redux
安装依赖
// redux 相关
yarn add redux react-redux redux-devtools-extension --save
这里安装了三个库:
redux
,react-redux
,redux-devtools-extension
-
redux
是 Redux 的原生核心库 -
react-redux
是 React 和 Redux 的绑定库(有额外的性能优化) -
redux-devtools-extension
是一个开发组工具库可以在浏览器上看到 store 里面的 state 的变化,方便调试!
这里例子使用了 Antd 组件库!
先定义 action
// redux/action/list/index.js
/**
* Action 类型
* 事件类型
*/
export const type = {
ADD_LIST: 'ADD_LIST'
}
/**
* 添加 List
* @description 也就是获取添加 List 操作类型, 以及携带的数据
* @param {*} data 携带的数据
*/
export function addList(data) {
return {
type: type.ADD_LIST,
data
}
}
定义 reducer
// redux/reducer/list/index.js
import { type } from '../../action/list'
// 数据仓库
const initialState = {
data: [
"这是第一行",
"这是第二行",
"这是第三行"
],
}
/**
* list 数据处理
* @param {*} state
* @param {*} action
*/
export default function list(state = initialState, action) {
switch (action.type) {
case type.ADD_LIST:
/**
* 处理完一些里操作后,返回一个新的 state
*/
// 把新的值,添加进 state
const newData = state.data.concat(action.data)
return {
...state,
data: newData
}
default:
return { ...state }
}
}
集中我们定义了一系列的 reducer 的函数
// redux/reducer/index.js
/**
* Reducer 数据处理
*/
import { combineReducers } from 'redux'
import list from './list'
/**
* 把多个 reducer 进行合并成一个
*/
export default combineReducers({
/**
* 写入一系列的 reducer
*/
list
})
创建 store
/**
* 创建数据源 store
*/
import { createStore } from 'redux'
import reducer from '../reducer'
import { composeWithDevTools } from 'redux-devtools-extension'
// 创建 store
// reducer 一定要是一个函数
// composeWithDevTools() 一定要写成这样,不能写成 composeWithDevTools
const store = createStore(reducer, composeWithDevTools())
export default store
创建 TodoList.js
import React, { Component } from 'react'
import { Input, Button, List } from 'antd';
import { connect } from 'react-redux'
import { addList } from '../redux/action/list'
/**
* TodoList 一个列表
*/
class TodoList extends Component {
constructor(props) {
super(props)
this.inpVal = React.createRef();
this.state = {
// data: [
// "这是第一行",
// "这是第二行",
// "这是第三行"
// ],
data: []
}
}
componentDidMount() {
this.setState({ data: this.props.list.data || [] })
}
componentDidUpdate(prevProps) {
// 典型用法(不要忘记比较 props)
if (this.props.list.data !== prevProps.list.data) {
this.setState({ data: this.props.list.data || [] })
}
}
addData() {
const { dispatch } = this.props
const inputValue = this.inpVal.current.state.value
console.log('当前值:', inputValue)
if (inputValue === undefined) {
return
}
// this.setState({ data: this.state.data.concat(inputValue) })
// 更新store
dispatch(addList(inputValue))
this.inpVal.current.state.value = undefined
}
render() {
// console.log('this.props: ', this.props)
return (
<>
<div style={{ margin: '10px' }}>
<div>
<Input ref={ this.inpVal } placeholder="请输入内容" style={{ width: '200px' }}/>
<Button type="primary" style={{ marginLeft: '10px' }} onClick={this.addData.bind(this)}>确认</Button>
<List
style={{ marginTop: '10px', width: '200px' }}
bordered
dataSource={this.state.data}
renderItem={(item, index) => (
<List.Item key={index}>
{item}
</List.Item>
)}
/>
</div>
</div>
</>
)
}
}
/**
* 把 store 里面 state 状态,附加到 props 上
* @param {*} state store的全局状态
* @param {*} ownProps 组件本身自己带的props
*/
const mapStateToProps = (state, ownProps) => {
/**
* 这里可以只拿取你需要的 state 里面的数据,这样可以节省性能开销
* 比如我这里只要 state 里面的 list
* 然后组件里面可以通过 props 获取 list 的值
*/
return { list: state.list }
}
/**
* connect 是一个容器
* 把 原有的组件进行装饰一下(装饰者模式)
*/
export default connect(mapStateToProps)(TodoList)
修改根目录下 index.js 文件
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import TodoList from './list/TodoList';
import { Provider } from 'react-redux'
import store from './redux/store/index'
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<Provider store={store}>
<TodoList />
</Provider>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
结果:
题外话:
结合实际项目开发的时候,redux
肯定是分为多个子模块
的。可以把 action
,reducer
拆分成多个!那么 reducer
拆分后,在定义一个统一的 reducer
文件进行合并!通过 redux 提供的 combineReducers
函数可以把多个子reducer
进行合并!
代码:https://github.com/weiximei/redux-demo
ps: 平常码云
用的最多!