大家好,我是梅巴哥er
。这是一篇规范的技术博客。本篇介绍redux
, react-redux
, redux
调试工具的一些学习总结。文章末尾另附一些简单的、便于理解的小案例。希望能对大家认识redux,能有更好的帮助。
Redux
1,官方文档: https://www.redux.org.cn/
2,因为redux
和react-redux
常常一起使用,所以两个文档在一起翻译的。
react-redux
官方文档: https://www.redux.org.cn/docs/react-redux/- PS: 如果想多看点关于redux的知识,可以看下阮一峰老师的讲解
3,Redux
是什么
redux
是一个独立的、专门用于做状态管理的JS库。不是react插件库。这一点要和react-redux
区分开。redux
可以用在react(angular, vue等)项目中,但基本是与react配合使用。- 作用:管理react应用中多个组件共享的状态
4,redux工作流程
如图:
解释:
- react组件中含有状态
state
- 不用redux的情况下,在react中更新状态的方法是
setState()
- 在
redux
中改变状态的步骤是:- 创建
action
,也就是组件所发生的事件。action里有事件名称type
和状态数据data
。 - 分发action(
即dispatch(action)
)给储存状态(state
)的仓库store
- 管理员
reducer
是个纯函数,负责处理管理仓库中的状态。reducer函数的参数是旧的状态
和action
。 - 管理员reducer把处理好的新状态交给仓库store
- react组件从仓库store中接收变化后的状态。完毕。
- 主要做的部分是分发action和reducer产生新的状态交给store。
- 创建
5,什么情况下需要使用redux
从组件角度来看:
- 某个组件的状态,需要共享
- 某个状态需要在任何地方都可以拿到
- 一个组件需要改变全局状态
- 一个组件需要改变另一个组件的状态
- 现在做完整项目基本上都要用,所以基本上可以不考虑。
6, 安装redux: npm install redux --save
7.1 creactStore()创建仓库
- 作用: 创建包含指定管理员reducer的仓库store
- 引入:
import {createStore} from 'redux'
- 引入创建好的管理员:
import counter from './reducers/counter'
- 创建仓库:
const store = createStore(couter)
7.2 store对象
-
作用: redux库最核心的管理对象
-
它管理了两个内容:
- state
- reducer
-
核心方法
getState()
// 获取当前状态dispatch(action)
// 分发事件(更新状态变化)subscribe(listener)
// 监听
-
代码:
-
store.getState()
-
store.dispatch({type: 'INCREMENT', number})
-
store.subscribe(render)
-
7.3 applyMiddleware()
-
作用: 应用上基于redux的中间件(插件库)
-
编码:
-
import {createStore, applyMiddleware} from 'redux'
-
import thunk from 'redux-thunk'
// redux异步中间件 -
const store = createStore( counter, applyMiddleware(thunk) // 应用上异步中间件 )
-
7.4 combineReducers()
- 作用: 合并多个reducer函数
- 代码
export default combineReducers({uer, chatUser, chat})
8, redux的三个核心概念
8.1 核心一: action
- action相当于一个事件对象,有事件名和事件内容。
- action对象的两个属性:
- type:事件类型,字符串类型,值唯一,必须具备的属性
- data:携带的数据,也就是事件内容,任意类型的值,可选属性
// action例子
const action = {
type: 'XIAOMING',
data: 18 // 或者age: 18
}
-
action函数,例如:
const increment = (number) => ({ type: 'INCREMENT', data: number }) // 解释: 为啥箭头后面是({...}) // 因为这个函数返回的是一个对象,用()把对象体包起来。 // 如果没有小括号,里面的{}就是函数体了。 /* 这里其实相当于 => { return ( { type: 'INCREMENT', data: number } ) } 单句返回体是可以省略最外层的{}和return的。 */
8.2 核心二: reducer
-
纯函数,根据老的state和action,产生新的state
// 举例 // 函数第一个参数state是一个状态的初始值,也就是初始状态initState // 即 state = initState export default function counter(state = 0, action) { switch(action.type) { case 'INCREMENT': return state + action.data case 'DECREMENT': return state - action.data default: return state } }
注意: 返回一个新的状态,不要修改原来的状态。
8.3 核心三: store
-
把state、action 与 reducer联系在一起的对象
-
如何得到store对象
import {createStore} from 'redux' import counter from './reducers' const store = createStore(counter) // 注意,创建store之后,store里面已经调用了管理员函数counter // 从管理员那里得到了初始state // 同时这个state是关联了管理员counter的 // 也就是说,store在创建的时候,就和管理员函数关联在一起了
-
store对象的功能
- getState():得到state
- dispatch(action): 分发action,触发reducer调用,产生新的state。达到更新状态的目的
- subscribe(listener):注册监听,当产生了新的state时,自动调用
React- Redux
1,首先声明:
react-redux
并不是redux的内置库,而是独立的一个库,需要单独安装:npm install react-redux --save
。只是因为两者经常要搭配使用,才放在一起说的。
2,react-redux把所有的组件分为两大类:
2.1 第一类: UI组件
- 只负责UI的呈现,不带有任何的业务逻辑
- 通过props接收数据(一般数据和函数)
- 不使用redux和react-redux的任何api
- 一般保存在
components
文件夹下
2.2 第二类: 容器组件
- 负责管理数据和业务逻辑,不负责UI呈现
- 使用Redux和react-redux的api
- 一般保存在
containers
文件夹下
3,react-redux有两个API
3.1 第一个API: <Provider store={store}>根组件</Provider>
- 用了Provider 以后,store就放在Provider 前面标签里面。它里面的所有组件都可以得到state数据了
- 根组件里就不需要加store了
- 注意,这里的根组件,就变成了connect所在的组件。因为Provider包含的根组件要始终和connect保持一致
- Provider 代替根组件来管理store。有Provider 才能用connect连接
3.2 第二个API: connect(reducer管理的状态, action函数)(连接的组件)
举例:
import {incrementAction, decrementAction} from '../redux/actions'
import {connect} from 'react-redux'
import App2 from '../components/App2'
// connect连接组件和redux
export default connect(
state => ({count: state}), // 这里的state是reducer管理的state,固定写法
{incrementAction, decrementAction} // 这俩是action函数。这里最好和声明接收的参数保持一致,就更简洁了。
)(App2) //App2是连接的组件
3.3 用了react-redux之后,和只用redux的不同之处
-
index.js入口文件,不再需要*store.subscribe(render)*监听。而是换成了用
<Provider store={store}>根组件</Provider>
。更方便了。 -
在原来的根组件中,需要引入PropTypes,用来声明接收数据的属性。
-
安装PropTypes包:
npm install prop-types
-
不再需要store.dispatch去分发action。而是直接用action的函数传值就可以了。
// 举例 // 用redux的写法: this.props.store.dispatch(decrementAction(number)) // 用了react-redux之后的写法: this.props.decrementAction(number)
-
UI组件和容器组件分开写了。
-
这里要注意根组件的变化
applyMiddleware(中间件)
-
redux默认是不能进行异步处理的,但是在实际应用中又需要在redux中执行异步任务,比如Ajax请求、定时器等。这时候就需要用到中间件
applyMiddleware(...middlewares)
。 -
可以自定义中间件,也可以用第三方包的中间件,如
thunk
-
安装:
npm install redux-thunk --save
-
引入:
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
applyMiddleware
为createStore
注入了middleware
// 例如
let store = createStore(reducer, applyMiddleware(thunk))
// 创建store的时候,()就有了两块内容,即管理员和中间件。这两个都是函数体。
-
在组件中写入action函数
this.props.xxxAction(number)
-
有引入和用到xxxAction的地方,记得该引入的引入,该添加的添加。
-
写对应的action函数。
同步
的action返回的是一个对象=> ({ })
,
// 同步action例子
export const incrementAction = (number) => ({
type: INCREMENT,
data: number
})
异步
action返回的是一个函数 => { }
,在返回的函数里面,执行异步代码。
// 异步action例子
export const incrementAsync = (number) => {
return dispatch => {
// 这里写异步代码
setTimeout(
// 分发同步action
// 每个异步action里,都有对应的分发同步action去改变状态
() => dispatch(increment(number))
, 1000)
}
}
Redux调试工具
1,在谷歌应用商店下载redux-devtools
-
记录一下我自己下载的保存的位置:
F:\前端资料\Desktop
2,打开Google浏览器,依次打开:设置-->更多工具-->扩展程序,打开,勾选开发者模式,点击 ‘加载已解压的扩展程序’
。把解压好的俩文件分别加载进去就好了。
这样就算好了。
3,下载工具依赖包redux-devtools-extension
npm install --save-dev redux-devtools-extension
4,在项目中编码,应用这个工具。放在store.js
文件里。
import { composeWithDevTools } from 'redux-devtools-extension'
const store = createStore(
counter,
composeWithDevTools(applyMiddleware(thunk))
)
// 也就是用composeWithDevTools把applyMiddleware(thunk)再包起来
5,看到google浏览器右上角的这俩图标,就算完成了。
左边是React的工具,右边是Redux的工具。
步骤可以再参考这篇介绍
6,打开使用。工具右上角会显示redux。
7,温馨提示
- 在写完项目后,记得关掉开发者模式的浏览器扩展程序,以免对电脑程序造成影响。
- 在写项目需要调试时,再到扩展程序里打开就行了。