redux-saga

redux-saga 一个用于管理Redux应用异步操作的中间件,使副作用(数据获取、浏览器缓存获取)易于管理、运行、测试和失败处理

npm i redux-saga -S
  1. redux-saga 通过创建sagas将所有异步操作逻辑收集在一个地方集中处理,可用于取代redux-thunk中间件;
    • redux-saga 可以处理各种复杂的异步操作,而redux-thunk只适用于简单的异步场景;
    • redux-saga 使用generator解决异步问题,使用同步方式编写异步逻辑,解决了回调地狱问题;
    • redux-thunk可以接收function类型的action,而redux-saga则是纯对象action
  2. redux-saga的工作成员
    • reducer负责actionstate更新;
    • sagas负责协调那些复杂或异步的操作。

基本用法

redux目录下:user.redux.js、sagas.js、index.js

  1. reducer函数:user.redux.js
    // 初始化state
    const initialState = {
        isLogin: false
    }
    // reducer
    export default (state = initialState, action) => {
        switch(action.type) {
            case 'login':
                return { isLogin: true }
            default:
                return state
        }
    }
    // redux 生成action的函数
    const login = function() {
        return { type: 'login_request' }
    }
    export { login }
    
  2. sagas.js
    import { call, put, takeEvery } from 'redux-saga/effects'
    const api = {
        login() {  // 模拟登录的接口
            //返回一个Promise
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    //随机数的方式判断是否登录成功
                    if(Math.random() > 0.5) {
                        resolve({ id: 1, name: 'Tim' })
                    } else {
                        reject({ message: '用户名或密码错误!' })
                    }
                }, 2000)
            })
        }
    }
    //工作的saga,ES6中的Generator生成器
    function* login(action) {
        try {
            // call 调用异步方法,开始登录,并接收登录返回的信息
            const res = yield call(api.login)
            // put 派发登录成功的 action,触发 reducer 函数
            yield put({ type:'login', res })
        } catch(err) {
            // put 派发登录失败的 action,触发 reducer 函数
            yield put({ type: 'login_fail', message: err.message })
        }
    }
    // 暴露出去的方法,执行工作的saga函数 login()
    function* mySaga() {
        // 事件监听:监听action
        yield takeEvery('login_request', login)
    }
    
    export default mySaga
    
  3. index.js
    import { createStore, applyMiddleware, combineReducers } from 'redux'
    import logger from 'redux-logger'
    import user from './user.redux'
    import createSagaMiddleware from 'redux-saga'
    import saga from './sagas'
    
    //1. 创建中间件
    const mid = createSagaMiddleware()
    //2. 应用中间件
    const store = createStore(
        combineReducers({ user }),  // combineReducers 用于 reducer 模块化
        applyMiddleware(mid, logger)  // 使用两个中间件:saga、redux-logger
    )
    //3. 执行saga,开始监听
    mid.run(saga)
    
    export default store
    
  4. 根组件中
    import {connect, Provider} from 'react-redux'
    import store from './redux/index'  //index可以省略 './redux'
    
    export default function App() {
        return (
            <BrowserRouter>
                <Provider store={store}>
                    <MainCompt></MainCompt>
                </Provider>
            <BrowserRouter>
        )
    }
    
  5. MainCompt.js
    import { connect } from 'react-redux'
    import { login } from './redux/user.redux'  //引入登录方法login()
    
    @connect(
        state=>({ isLogin: state.user.isLogin })  // 传递redux中的state
    )
    class RouteGuard extends Component {  //路由守卫
        render() {
            const {component:Component, ...otherProps} = this.props
            return (
                <Route {...otherProps} render={props => (
                    //根据redux中的state isLogin变量判断是否登录,没有登录则重定向到登录页
                    this.props.isLogin ? <Component {...props}></Component> : 
                    (<Redirect to={{ pathname:'/login', state:{from:props.location.pathname} }} />)
                )}></Route>
            )
        }
    }
    
    @connect(
        state=>({isLogin:state.user.isLogin}),  // 传递redux中的state { isLogin: true/false }
        { login }
    )
    class Login extends Component {  //登录组件
        render() {
            const from = (this.props.location&&this.props.location.state&&this.props.location.state.from) || '/'
            if(this.props.isLogin) {
                return <Redirect to={from} />  // 已经登录了,重定向到守卫的路由,否则重定向到"/"
            }
            // 尚未登录
            return (
                <div>
                    <h2>请先登录</h2>
                    <button onClick={this.props.login}>登录</button>
                </div>
            )
        }
    }
    
    export default class MainCompt extends Component {
        constructor(props) { super(props) }
        render() {
            return(<BrowserRouter>
                <div>
                    <header>
                        <NavLink to="/">首页</NavLink>
                        <NavLink to="/news">新闻</NavLink>
                        <NavLink to="/login">登录</NavLink>
                        <NavLink to="/mine">我的</NavLink>
                    </header>
                    <Switch>
                        <Route exact path="/" component={Home} />
                        <Route path="/news" component={News} />
                        <Route path="/login" component={Login} />
                        <RouteGuard path="/mine" component={Mine} />
                    </Switch>
                </div>
            </BrowserRouter>)
        }
    }
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1. redux-thunk处理副作用的缺点 1.1 redux的副作用处理 redux中的数据流大致是: UI—...
    Grace_ji阅读 3,677评论 0 14
  • 最近项目用了dva,dva对于异步action的处理是用了redux-saga,故简单学习了下redux-saga...
    笨人不能懒阅读 3,012评论 0 5
  • 原文地址在我的博客, 转载请注明出处,谢谢! 概述 本文介绍了我对 Redux 状态管理的思想、原理、架构方法的认...
    莫凡_Tcg阅读 7,125评论 0 15
  • 从数据到界面响应流程用户在界面上操作,发起action,action在reducer中改变store上的数据,或者...
    Lethe35阅读 787评论 0 1
  • 一切优秀的框架都是为程序员服务的:reactjs提供更优雅的前端代码书写方式和更优的界面更新机制,react-na...
    DumpCicada阅读 22,675评论 0 22

友情链接更多精彩内容