1,Redux-Saga简述:
redux-saga是redux的中间件,主要负责处理从action派发到更新store装填中间具有副作用行为的处理。
2,开始使用Redux-Saga
-
下面是react的入口文件,我们使用了redux,react-redux进行状态管理,并使用了redux-saga中间件。
// 当前路径:src/index.js // 第三方模块引入 import React from 'react' import ReactDom from 'react-dom' import { Provider } from 'react-redux' import { createStore, applyMiddleware } from 'redux' import createSagaMiddleware from 'redux-saga' // 自定义模块引入 // 1,redux中的 reducer引入 import rootReducer from './LearningSaga/reducer' // 2,react中 Counter组件引入 import Counter from './LearningSaga/component' // 3, redux-saga中间件的 saga文件引入 import rootSaga from './LearningSaga/saga' // 4,创建一个redux-saga中间件 const sagaMiddleware = createSagaMiddleware() // 5,将redux-saga中间件加入到redux中 const store = createStore(rootReducer, {}, applyMiddleware(sagaMiddleware)) // 6,动态的运行saga,注意 sagaMiddleware.run(rootSaga) 只能在applyMiddleware(sagaMiddleware)之后进行 sagaMiddleware.run(rootSaga) // 7,挂载react组件 ReactDom.render(<Provider store={store}><Counter /></Provider>, document.getElementById('root'))
-
注释1是我们要用到的reducer,下面是reducer文件内容,很简单,我们创建了counterReducer,并使用redux提供的combineReducers处理并返回出去,熟悉redux使用的话,这里应该不用太多赘述,就是一个简单的对state.counter进行递增处理的reducer。
// 当前路径:src/LearningSaga/reducer/index.js import { combineReducers } from 'redux' function counterReducer(state = 1, action = {}) { switch (action.type) { case "increment": return state + 1; default: return state } } const rootReducer = combineReducers({ counter: counterReducer }) export default rootReducer
-
注释2是我们react挂载的一个Counter组件,下面是Counter组件代码,也是个很简单的组件,其中使用了react-redux对Counter进行处理,这样就能在this.props中获取到redux中的状态以及dispatch方法。
// 当前路径:src/LearningSaga/component/index.js import React from 'react' import { connect } from 'react-redux' class Counter extends React.Component { // 派发一个type为 increment_saga 的action add = () => this.props.dispatch({ type: 'increment_saga' }) render() { return ( <div> <span>{this.props.counter}</span> <button onClick={this.add}>add1-sync</button> </div> ) } } const mapStateToProps = state => ({ counter: state.counter }) export default connect(mapStateToProps)(Counter)
-
注释4567完成了对redux创建,redux中redux-saga中间件的使用,以及Counter组件的挂载等。当然这里redux-saga中间件处理方式可能和其它中间件方式略有不同。
-
在讲注释3之前我们先回顾一下Counter组件的使用,首先Counter组件渲染出store(redux)中counter数据和一个递增按钮add1-sync,点击该按钮将派发一个类型为increment_saga的action。我们期待的事 是该动作派发后,store中的counter数据能够加1,其实如果仅是如此,我们派发一个类型为increment的action就可以做到,因为我们在注释1的reducer中已经实现了对类型为increment的action处理。但我们这里要用redux-saga中间件替我们完成,我们可以想一下redux-saga中间件要完成这个加1行为大概要做怎样一件事,首先,拦截到action,然后做一些处理,最后更新store中的counter数据完成+1。没错,redux-saga中间件的流程就是这样,所以按照这个流程回头看,这里我们派发一个类型为increment_saga的action,redux-saga中间件获取到该action,因为这个行为很纯粹就是+1,redux-saga中间件再继续调用
dispatch({type:'increment'})
完成对store中counter数据+1。 -
现在回到注释3,这是redux-saga中saga文件,下面是该文件的代码,我们看到该文件中的函数全是generator函数,没错,redux-saga的世界中,就是通过这些generator函数完成dispatch过程中副作用的处理(当然我们现在这个+1例子中还没涉及到一些强烈具有副作用的行为),这些generator函数我们叫它saga。saga中yield 后面的内容我们称呼它为Effects(redux-saga的任务单元),在Effects中我们可以进行启动其它saga,也可以处理一些副作用操作。
// 当前路径:src/LearningSaga/saga/index.js import { all, put, takeEvery } from 'redux-saga/effects' function* increment() { // 相当于:dispatch({ type: 'increment' }) yield put({ type: 'increment' }) } function* watchIncrement() { // 监听类型为increment_saga的action,监听到启动increment yield takeEvery('increment_saga', increment) } function* rootSaga() { // 启动watchIncrement yield all([watchIncrement()]) } export default rootSaga
-
这里我们导出的是一个rootSaga函数,该函数内容很简单,只有一行
yield all([watchIncrement()])
,其中all是redux-saga所提供的一个方法,用来启动一个或多个Effects,这里我们只启动了一个watchIncrement的saga。 -
继续看watchIncrement这个saga,函数内容仅有一行
yield takeEvery('increment_saga', increment)
,其中takeEvery是redux-saga提供的一个方法,该方法传入两个参数(type,saga),其中type即对应action中的type,而saga则是redux-saga中间件匹配到对应type的action时需要启动的saga。所以这行代码的作用很简单,就是监听action类型为increment_saga,并启动对应saga进行处理该action。 现在假设watchIncrement监听到类型为increment_saga的动作,启动increment这个saga进行处理。我们进入increment函数中看看做了什么。 -
increment这个saga中也仅有一行代码
yield put({ type: 'increment' })
,这行代码中put也是redux-saga提供的一个方法,其参数为一个action,其作用是产生一个dispatch行为的Effect,其action就是put中的参数action。我们可以理解这个动作就相当于dispatch({ type: 'increment' })
。所以这里将派发一个类型为increment动作去更新store中的state。 -
现在整个saga文件已经介绍完它的作用,我们来复盘从Counter组件点击add1-sync按钮那一刻到最后store中的counter数据加1的流程。
-
1,react入口文件中注释6启动了rootSaga,rootSaga执行
yield all([watchIncrement()])
,即启动了watchIncrement这个saga,并等待它运行完成 -
2,watchIncrement的作用在前面说了,是监听类型为increment_saga的action,如果监听到,则启动increment这个saga对action进行进一步处理。
-
3,现在Counter组件中add1-sync按钮点击,派发一个类型为increment_saga的动作。
-
4,watchIncrement这个saga监听到该动作(type:'increment_saga'),启动increment对该action进行处理。
-
5,increment中通过
yield put({ type: 'increment' })
派发一个类型为increment的action出去 -
6,reducer接受到类型为increment的action,执行对应的更新行为,完成store中counter数据+1的过程。
-
7,最后更新Counter组件中的
this.props.counter
数据(这个自动更新行为由react-redux替我们完成)。
-
-
3,带有副作用的counter数据更新
-
在原Counter组件上新增add1-async按钮
// 当前路径:src/LearningSaga/component/index.js import React from 'react' import { connect } from 'react-redux' class Counter extends React.Component { add = () => this.props.dispatch({ type: 'increment_saga' }) // addAsync函数将派发一个类型为incrementAsync_saga的action addAsync = () => this.props.dispatch({ type: 'incrementAsync_saga' }) render() { return ( <div> <span>{this.props.counter}</span> <button onClick={this.add}>add1-sync</button> <button onClick={this.addAsync}>add1-async</button> </div> ) } } const mapStateToProps = state => ({ counter: state.counter }) export default connect(mapStateToProps)(Counter)
-
我们也要在saga文件中添加incrementAsync_saga动作对应的saga进行处理
// 当前路径:src/LearningSaga/saga/index.js import { all, put, takeEvery, delay } from 'redux-saga/effects' function* increment() { yield put({ type: 'increment' }) // 相当于:dispatch({ type: 'increment' }) } function* incrementAsync() { // 延迟1s yield delay(1000) // 1s后,dispatch({ type: 'increment' }) yield put({ type: 'increment' }) } function* watchIncrement() { yield takeEvery('increment_saga', increment) // 监听类型为increment_saga的action,监听到启动increment // 监听类型为incrementAsync_saga的action,监听到启动incrementAsync yield takeEvery('incrementAsync_saga', incrementAsync) } function* rootSaga() { yield all([watchIncrement()]) // 启动watchIncrement } export default rootSaga
-
我们在watchIncrement添加了新的一行代码
yield takeEvery('incrementAsync_saga', incrementAsync)
,上一节中学习我们知道,这行代码作用是 监听类型为incrementAsync_saga的action,监听到启动incrementAsync。 -
继续看incrementAsync,相较于之前的increment,多了一行代码
yield delay(1000)
,其中delay是redux-saga提供的延迟函数,该行代码表示延迟1s后才可以继续处理之后的代码。其本质可以看做这么个函数。// delay 相当于这里的 delay_ function delay_(timeout) { return new Promise(r => { setTimeout(() => r(), timeout); }) }
-
所以延迟1s后,继续执行
yield put({ type: 'increment' })
,即相当于dispatch({ type: 'increment' })
完成counter更新。
-
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!