redux是什么?
Redux 是 JavaScript 状态容器,提供可预测化的状态管理
官网说如果你不知道你的项目中什么时候需要使用到,那就是不需要使用,当你发现react中有你无法解决的事时,那就考虑是否需要使用Redux了
好了,下面就让我们一起来看看Redux究竟是干什么的,以及怎么使用它。
Redux工作流
先来看这张图,它很好的解释了redux的工作机制
- view发出action,要求改变state;
- state都存储在store这个库中,那么就需要store给出new state,action交由diapatch统一分发给store;
- store交由reducer去计算并返回newState,reducer函数接收两个参数,action,旧state,reducer函数是纯函数,所有只进行纯函数的运算,不能进行副作用操作,这也就是官网说的 “可预测”态管理
- 最后,store通过监听器得知已返回newSatete,并进行视图更新
还是很好理解的吧,其实上述也已经可以总结出redux的三大原则
- 单一数据源
- State 是只读的
- 使用纯函数来执行修改 说了理论的,现在来实现一个累加器吧
//actionType.js 这里用大写字母存储避免出错,也更容易进行debugger
export const ADD = 'add'
export const MIXIS = 'mixis'
// reducer.js
import { ADD,MIXIS } from './actionType'
import { combineReducers } from 'redux'
const countReducer = (state = 0,action) => {
switch(action.type){
case: 'ADD':
return state ++
case 'MIXIS':
return state --
default:
return state
}
}
const rootReducer = combineReducers({
countReducer
})
export defalut rootReducer
// 根目录下 store.js
import { createStore } from 'redux'
import rootReducer from './reducer'
const store = createStore(rootReducer)
expoer default store
// page.js
import React,{ Component } from 'react'
import store from './store'
class Page extends Component {
componentDidMount() {
// 当监听到state变化时,执行强制更新
this.unsubscribe = subscribe((listen) =>listen() )
this.forceUpdate()
}
componentWillOnMount() {
// 卸载监听器
if(this.unsubscribe) {
this.unsubscribe()
}
}
add = () => {
store.dispatch('add')
}
mixis = () => {
store.dispatch('mixis')
}
render() {
return (
<div>
<p>{store.getState()}</p>
<button onClick={this.add}>加</button>
<button onClick={this.mixis}>减</button>
</div>
)
}
}
这就是redux的基本使用方法,上面说了reducer是纯函数,不能进行副作用操作,那如果我们想要进行数据请求或者延迟操作或者日志打印在怎么办呢?思考一下,咱们接着往下看
异步机制
createStore接收三个参数 createStore(reducer, [preloadedState], enhancer),第一个是reducer咱们上面已经用了,后面两个是可选参数,第二个是初始值,第三个参数是增强器,也就是处理异步需要用到的函数。 咱们对上述代码进行异步处理更改
// page.js
import React,{ Component } from 'react'
import store from './store'
class Page extends Component {
....
// add = () => {
// store.dispatch({'add'})
// }
// 更改为
asyncAdd = () => {
store.dispatch( () =>
// 原本dispatch值接收一个对象,经过增强后可以接收一个函数
setTimeout(() => {
store.dispatch({'add'})
}, 1000);
)
}
render() {
return (
<div>
<p>{store.getState()}</p>
<button onClick={this.asyncAdd}>加</button>
</div>
)
}
}
当然还可以进行其他副作用操作... 上面是redux的操作流程,它可以在很多框架中使用,那在react中如何使用呢?
React-Redux
小伙伴们有没有想过我们把状态存储在store中,但是要进行数据间的传递怎么办呢,能不能把数据挂载在全局,这样大家就可以根据自己想要的去读取,嗯react-redux就提供了这样的便利
// 根文件下 indx.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import { Provider } from "react-redux";
import store from "./store";
import App from "./App";
ReactDOM.render(
// Provider 相当于一个全局容器,它的子组件都可以访问到 其底层功能相当于context中的提供者和消费者思想,没用的小伙伴可以去看一下有助于理解
<Provider store={store}>
// 真实项目中这里应该是routes 组件而不是单一的app组件
<APP />
</Provider>
,
document.getElementById("root")
);
import React,{Component} from 'react'
import {connect} from 'connect'
class Home extends Component {
constructor(props){
super(props)
}
render() {
return (
<div>
<p>{this.props.count}</p>
</div>
)
}
}
const mapStateToProps = () => {
state => state.count
}
const mapDispatchToProps = (dispatch) =>{
return {
add: () => dispatch(add())
}
}
export defalut connect(mapStateToProps,mapDispatchToProps)(Home)
相信小伙伴们现在都知道怎么使用了,那内部是如何实现的呢?下面咱们来一探究竟
源码
export defalut function createStore(reducer) {
// 根据上述事例,可以知道createStore接收的第一个参数是reducer
let initialState = null // 设置初始值为null
let initialListeners = [] // 给监听一个空数组,每触发一次就push
function getState() {
// getState 方法很简单,最后就是返回state
return initialState
}
function dispatch (action) {
initialState = reducer(initialState,action)
initialListeners。forEach(listener => listener()) // listener 每当 dispatch action 的时候都会执行的回调
}
function subscribe(listener) {
initialListeners.push(listener)
// 当取消监听的时候,将数组置空
return () => {
initialListeners = []
}
}
return {
// 最后返回的是store 以下是store有三个方法,最后导出,这几个方法咱们也需要手动实现以一下
getState, // 获取状态
dispatch, // 触发改变state
subscribe // 订阅
}
}
这样就可以引入这个文件替代react我们的方法进行使用了,这次只讲到createStore的一个参数使用,下篇咱们来讲讲如果有增强器enhancer,改如何写,可以思考一下哦