这篇博客是看一个网上视频的笔记,后面也会根据自己在项目开发过程中遇到的问题进行不断的更新。
目录
Redux概述
什么是Redux
Redux的设计初衷
Redux三大核心
1、单一数据源
2、state是只读的
3、使用存函数来执行修改
Redux组成部分
state状态
action
reducer
Store
Redux案例
react-redux
Redux是一个用于Javascript状态容器,可以进行全局状态管理。
Redux可以构建一致化的应用,运行与不同的环境(客户端,服务器,原生应用),并且易于测试。
Redux除了和React一起使用外,还支持其他界面库,而且它体积很小(2KB)。
随着Javascript单页面开发日益复杂,Javascript需要管理更多的state(状态),这些state可能包括服务器响应、缓存数据、本地生成未持久化到服务器的数据,也包括UI状态等。
管理不断变化的state非常麻烦,如果一个model的变化会引起另外model的变化,那么当view发生变化时,就可能引起对应model以及另一个model的变化,依次可能引起其他view的变化,所以逻辑处理就会比较混乱。而Redux就为了解决这个问题的。Redux可以进行全局状态管理。
整个应用的state都被保存在一个object tree中,Object Tree只存在于唯一的一个store中。
说state是只读的,并不意味着state不能修改。
如果修改state需要触发一个action。action是一个用于描述已发生事件的普通对象。
这样确保了视图和网络请求都不能直接去修改state。它们只能表达想要修改的意图。所有的修改都会被集中化处理,并且按照一个接一个的顺序执行。
为了描述action如何改变state,需要编写reducers。
reducers是一些纯函数,它接收先前的state和action,并且返回新的state。
可以复用、控制顺序、传入附加参数。
state就是我们传递的数据。state可以分为三类:
(1)DomainDate:从服务器请求到的数据
(2)UI state:控制UI展示的状态,比如弹框的显示隐藏等
(3)App state:App级别的状态,比如路由信息可以被多个组件使用到的状态
action是把数据从应用传到store载体,它是store数据的唯一来源,可以通过store.dispatch()将action传递给store
reducer本质就是一个函数,可以响应发送过来的action,经过处理,将state发送给store。
注意:在reducer函数中,需要return返回值,这样store才能接收到数据。
函数会接收两个参数,第一个参数是初始化state,第二个是action
store就是把action与reducer联系到一起的对象。
store维持应用的state状态,提供getState()方法获取state,提供dispatch()方法发送action,通过subscribe()注册监听,通过subscribe()返回值注销监听
组件component通过action载体向store中发送数据,store通过reducers将新的state存到store中,其他组件就可以从store中拿到新的state状态。
类似于去图书馆借书的流程
构建项目之后,安装redux,安装命令:
npm i redux
在scr文件夹下创建action文件夹,并在action文件夹下创建index.js文件。在index.js中通过创建一个函数,返回一个aciton对象,其中action对象中必须要有type属性。
/**
* action 构建函数
*/
export const sendAction = () => {
// 需要返回一个action对象,该action对象需要包括type等属性
return {
type: 'send-action',
value: '这是一个action'
}
}
接着在src文件夹下创建reducer文件夹,在reducer文件夹中创建index.js文件。在index.js文件中处理action,通过return将数据传给store.
/**
* 该文件是创建reducer函数,专门用于处理发送过来的action
*/
const initState = {
value: '默认值'
}
// 函数需要传递两个参数:state,action
const rootReducer = (state = initState, action) => {
console.log('reducer:', state, action)
// 根据aciton中的type字段判断是否为发送过来的action,如果是则返回一个新的state
switch (action.type) {
case 'send-action':
return Object.assign({}, state, action)
default:
return state
}
}
export default rootReducer;
接着利用createStore来构建store,createStore方法中传入reducer。
import { createStore } from 'redux'
import { rootReducer } from '../reducer';
const store = createStore(rootReducer)
export default store;
在Home组件中通过store.subscribe()注册监听,当利用store.dispatch()发送action时就会触发监听,然后就可以通过store.getState()方法获取数据
import React from "react";
// 引入store
import store from '../../store'
// 引入action构建函数
import {sendAction} from '../../action'
export default class Home extends React.Component {
constructor(props) {
super(props)
}
sendAction() {
// 通过sendAction创建一个action
const action = sendAction()
// 发送一个action
store.dispatch(action)
}
componentDidMount() {
// 注册监听
this.unsubscribe = store.subscribe(() => {
// 通过getState()方法获取state
console.log('subscribe: ', store.getState())
// 获取到监听之后,可以通过this.setState()方法触发页面重新渲染
this.setState({})
})
}
componentWillUnmount() {
// 取消监听
this.unsubscribe()
}
render() {
return (
store获取的值:{store.getState().value}
)
}
}
结果:
未点击发送action之前:
点击发送aciton之后:
上面的示例,我们会发现每创建一个store,我们就需要导入该store,并且要注册/取消监听,比较麻烦,react-redux为我们解决了这个问题。
第一步:安装依赖:
npm install redux
npm install react-redux
第二步:按redux的示例创建action、reducer、store等方法,然后创建两个组件,并引入到app.js中。
第三步:引入Provider
在app.js中引入react-redux库中的Provider组件,用Provider组件包裹项目结构,并给Provider设置store属性,传入我们创建的store。这样Provider就可以统一维护store了。
import CompA from "./page/CompA";
import CompB from "./page/CompB";
import store from '../src/store'
// 导入Povider组件,利用这个组件包裹项目结构,从而统一维护store
import { Provider } from "react-redux";
function App() {
return (
// 为Provider传入store
);
}
export default App;
第三步:使用react-redux库中的connect
Provider只是维护store,真正使用store还需要connect。connect可以把组件和store进行关联。
connect的使用方法的简单介绍:
使用方法:connect(...)(组件)
ps:connect(...)返回的是一个方法,所以才能继续跟(组件)
connect(...)的参数说明:
具体详情可以查看react-redux官方文档对connect的讲解
其中mapStateToProps和mapDispatchToProps比较重要。
mapStateToProps: (state, ownProps?) => Object,哪个组件需要接收store的数据,就实现该方法,如果不想订阅store更新可以传入null或者undefined代替mapStateToProps
mapDispatchToProps?: Object | (dispatch, ownProps?) => Object,哪个组件需要发送store数据,就实现该方法。
发送方CompA
import React from "react";
// 导入connect方法
import { connect } from "react-redux";
class CompA extends React.Component {
addCount() {
console.log('CompA: ', this.props)//由日志可以发现sendAction会被传过来
// 所以我们就可以利用sendAction发送数据
this.props.sendAction()
}
render() {
return (
CompA组件:
)
}
}
//创建mapDispatchToProps方法-使用箭头函数实现,最后action会被作为一个props传递给组件
const mapDispatchToProps = (dispatch) => {
// 需要返回一个对象
return {
// 对象使用key-value的形式。另外根据对redux使用可以知道sendAction也是一个方法实现
sendAction: () => {
// 利用dispatch发送一个action
dispatch({
// action必须要有type属性
type: 'add-action'
})
}
}
}
/*
CompA是数据发送方,所以要实现connect的第二个参数mapDispatchToProps
*/
export default connect(null, mapDispatchToProps)(CompA)
接收方CompB
import React from "react";
// 导入connect方法
import { connect } from "react-redux";
class CompB extends React.Component {
render() {
return (
CompB组件接收到的数据:{this.props.count}
)
}
}
const mapStateToProps = (state) => {
// 在这里必须要return state
return state
}
// 接收方
export default connect(mapStateToProps, null)(CompB)
reducer:
const initState = {
count: 0
}
export const rootReducer = (state = initState, action) => {
console.log('reducer:', state, action)
switch (action.type) {
case 'add-action':
// 在reducer中返回了新的state,才能触发相关的接收组件获取新的数据
return {
count: state.count + 1
}
default:
return state
}
}
store
import { createStore } from 'redux'
import { rootReducer } from '../reducer';
const store = createStore(rootReducer)
export default store;
数据传递流程