React中的redux-saga详解

这篇具有很好参考价值的文章主要介绍了React中的redux-saga详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


1. 介绍

redux-saga 是 redux 一个中间件,它是基于ES6 的 Generator 功能实现,用于解决异步问题(让redux中可以直接进行异步操作)。

React中的redux-saga详解

组件会发送一个 action 对象给 redux-saga,redux-saga(主saga) 就会分析监听 saga 中有没有当前 action 对应的 type 类型操作,如果在监听 saga 中找到了,说明当前操作是一个异步操作,然后就会走下面的异步操作流程,最后 action 会被交给 redux,也就是交给 reducer 完成修改。

如果主 saga 在监听 saga 没有找到对应 type 的实现,则说明当前操作是一个同步操作,就会直接交给 redux。

2. redux-saga安装和在项目中引入配置

安装:

yarn add redux-saga

在项目中引入:

store/index.js:

import { createStore, applyMiddleware } from 'redux'
import { composeWithDevTools } from '@redux-devtools/extension'
// 中间件
// import thunk from 'redux-thunk'

// 合并后的reducer
import reducer from './reducer'

// saga中间件
import createSagaMiddleware from 'redux-saga'
import mainSaga from './sagas'

const sagaMiddleware = createSagaMiddleware()

const store = createStore(reducer, composeWithDevTools(applyMiddleware(sagaMiddleware)))

// 运行saga
sagaMiddleware.run(mainSaga)

export default store

sagas.js:

// saga中间件 主saga,用于区别是否需要saga来处理异步操作,如果没有异步,则放行
function* mainSaga() {

}

// 监听saga,监听type类型为异步操作名称的,此saga会通过主saga分配过来
function* watchSaga() {

}

// 工作saga,监听saga得到任务后,把任务分配给工作saga
function* workSaga(action) {

}

// 主saga要对外暴露出去
export default mainSaga

3. redux-saga的使用

用 resux-saga 写一个延时计数器。

App.jsx:

import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
// useSelector : 读取redux的state的数据
// useDispatch : 修改redux的state的数据

const Login = () => {
  const dispatch = useDispatch()
  let num = useSelector(state => state.count.num)

  return (
    <div>
      <h3>{num}</h3>
      <button onClick={() => dispatch({ type: 'asyncAdd', payload: 10 })}>进入系统</button>
    </div>
  )
}

export default Login

sagas.js:

import { takeEvery, put } from 'redux-saga/effects'
// put 它是saga提供给我们,用于发送指令给reducer来完成同步操作
// takeEvery 监听每一次dispatch发送的指令

// 延时器
function delay(n = 1) {
  return new Promise(_ => {
    setTimeout(() => _(''), 1000 * n)
  })
}

// saga中间件 主saga,用于区别是否需要saga来处理异步操作,如果没有异步,则放行
function* mainSaga() {
  // 这样的调用,它只能监听一个saga,不能进行模块化
  yield watchSaga()
}

// 监听saga,监听type类型为异步操作名称的,此saga会通过主saga分配过来
function* watchSaga() {
  yield takeEvery('asyncAdd', workSaga)
}

// 工作saga,监听saga得到任务后,把任务分配给工作saga
// function* workSaga(action) {
function* workSaga({ payload }) {
  // 异步请求
  yield delay(2)
  // 发送指令让reducer完成同步操作
  yield put({ type: 'add', payload })
}

// 主saga要对外暴露出去
export default mainSaga

count.js:

const initState = {
  num: 100
}

const reducer = (state = initState, { type, payload }) => {
  if ('add' === type) return { ...state, num: state.num + payload }
  return state
}

export default reducer

React中的redux-saga详解

4. saga模块化拆分

在这一章节中,我们将要实现 saga 的模块化拆分。我们的需求是,点击登录系统之后,可以获取到 uid ,获取到 uid 之后可以跳转到后台首页。

首先我们需要 mock 一下后台的用户数据:

user.js:

module.exports = app => {
  // 用户登录
  app.post('/api/login', (req, res) => {
    let bufferData = []
    // 如果你要在mock时想要接受post数据
    req.on('data', chunk => bufferData.push(chunk))
    req.on('end', () => {
      // username=xxx&password=xx
      let postString = Buffer.concat(bufferData).toString('utf-8')

      res.send({
        code: 0,
        msg: 'ok',
        data: {
          uid: 2000,
          token: 'fwe;fjewlfjlwfjlefewlfelffewlfewjfe',
          nickname: '张英',
        }
      })
    })
  })
}

然后是 api 接口的书写:

userApi.js:

import { post } from '@/utils/http'

// 用户登录
export const loginApi = userData => post('/api/login', userData)

然后是 redux 中的 reducer 函数:

user.js:

const initState = {
  uid: 0,
  token: '',
  nickname: ''
}

const reducer = (state = initState, { type, payload }) => {
  // reducer函数处理 userlogin 类型的 action
  if ('userLogin' === type) return { ...state, ...payload }
  return state
}

export default reducer

接下来是主 saga 文件:

sagas.js:

import { all } from 'redux-saga/effects'
// all方法,可以监听多个监听saga,它的功能和Promise.all方法一样

import userWatchSaga from './watchsagas/userSaga'

// saga中间件 主saga,用于区别是否需要saga来处理异步操作,如果没有异步,则放行
function* mainSaga() {
  yield all([
    // 监听 saga 中有 userWatchSaga 操作,所以会拦截这个 action
    userWatchSaga()
  ])
}

export default mainSaga

监听 saga :
userSaga.js:

import { put, takeEvery, call } from 'redux-saga/effects'
// put 它是saga提供给我们,用于发送指令给reducer来完成同步操作
// takeEvery 监听每一次dispatch发送的指令

// call方法,调用Promise对象
//  引入网络请求方法
import { loginApi } from '@/api/userApi'

export default function* watchSaga() {
  yield takeEvery('asyncLogin', login)
}

// 在此处完成网络请求就可以了
// generator的返回值,不是普通函数这样的返回值,这样在登录成功后,无法让前端的组件完成路由的切换,
// 切换的原则是登录成功后,才能能跳转,登录的过程它是一个异步的,所以此时工作就有点难受,所以需要用到库
function* login({ payload }) {
  // call内部实现了 co 方法,可以将自己的返回值返回给 ret
  let ret = yield call(loginApi, payload)
  // 得到的数据同步到redux中
  if (ret.code === 0) {
    // 通过reducer完成redux中的数据更新  登录成功
    yield put({ type: 'userLogin', payload: ret.data })
  }
}

最后是我们的前台页面:

import React, { useEffect } from 'react'
// react-redux提供的hook工具函数
import { useDispatch, useSelector } from 'react-redux'
// useSelector : 读取redux的state的数据
// useDispatch : 修改redux的state的数据

const Login = ({history}) => {
  const dispatch = useDispatch()
  let num = useSelector(state => state.count.num)
  let uid = useSelector(state => state.user.uid)

  // hack处理方案,完成登录成功后,路由跳转
  // 只要 uid 发生改变(由零变为2000),这个函数就被触发
  useEffect(() => {
    // uid初始值为0,只要你登录成功,则一定会大于0,表示登录成功,跳转到后台
    if (uid > 0) history.push('/')
  }, [uid])

  const doLogin = () => {
    // 进行登录,它是一个异步的,交给saga,saga会完成异步操作,通知reducer完成同步修改redux中的state数据改变
    // reducer把state中的数据修改后,因为我在当前的组件中有通过useEffect来依赖此state中的值的变化,所以它只要变化了,我就可以来跳转,从而可以确认redux中的数据一定是存在后才跳转的
    dispatch({ type: 'asyncLogin', payload: { username: 'admin', password: 'admin888' } })
  }

  return (
    <div>
      <h3>
        {num} -- {uid}
      </h3>
      <button onClick={doLogin}>进入系统</button>
    </div>
  )
}

export default Login

React中的redux-saga详解

5. connected-react-router

描述:

此库可以让redux中完成路由跳转相关的功能。

安装:yarn add connected-react-router

使用步骤:

  1. 在 src 目录下创建 history.js 文件,并书写如下代码:

    // history模块它是react-router-dom安装成功后就存在的,无需手动再安装
    import { createBrowserHistory, createHashHistory } from 'history'
    const history = createBrowserHistory()
    // 告知当前路由的模式为 history模式
    export default history
    
  2. 在入口文件中把原来的react-router-dom中定义路由模式组件更换:

    import React from 'react'
    import ReactDOM from 'react-dom'
    
    // 路由
    // import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
    // 使用connected-react-router库,就需要把原来的路由模式组件进行更换
    import { ConnectedRouter as Router } from 'connected-react-router'
    import history from './history'
    
    // redux
    import { Provider } from 'react-redux'
    import store from './store'
    
    import App from './App'
    
    // 后台首页
    
    ReactDOM.render(
      <Provider store={store}>
        <Router history={history}>
          <App />
        </Router>
      </Provider>,
      document.getElementById('root')
    )
    
  3. 在 reducer 模块中,定义一个 router 的模块

    import { combineReducers } from 'redux'
    import { connectRouter } from 'connected-react-router'
    import history from '@/history'
    
    import user from './user'
    import count from './count'
    
    export default combineReducers({
      // 添加一个 router 的模块
      router: connectRouter(history),
      user,
      count
    })
    
  4. 在redux入口文件中,以中间件的方式把connected-react-router包含到redux中

    import { createStore, applyMiddleware } from 'redux'
    import { composeWithDevTools } from '@redux-devtools/extension'
    // 中间件
    // import thunk from 'redux-thunk'
    
    // 合并后的reducer
    import reducer from './reducer'
    
    // saga中间件
    import createSagaMiddleware from 'redux-saga'
    import mainSaga from './sagas'
    
    // redux中路由
    import { routerMiddleware } from 'connected-react-router'
    import history from '@/history'
    
    const sagaMiddleware = createSagaMiddleware()
    
    // 在redux入口文件中,以中间件的方式把connected-react-router包含到redux中
    const store = createStore(reducer, composeWithDevTools(applyMiddleware(routerMiddleware(history), sagaMiddleware)))
    
    // 运行saga
    sagaMiddleware.run(mainSaga)
    
    export default store
    
  5. 在 redux 中间件中就可以完成路由跳转:

    userSaga.js:

    import { put, takeEvery, call } from 'redux-saga/effects'
    // put 它是saga提供给我们,用于发送指令给reducer来完成同步操作
    // takeEvery 监听每一次dispatch发送的指令
    
    // 通过库,可以完成在redux中实现跳转跳转功能
    import { push, replace, goBack } from 'connected-react-router'
    // call方法,调用Promise对象
    //  引入网络请求方法
    import { loginApi } from '@/api/userApi'
    
    export default function* watchSaga() {
      yield takeEvery('asyncLogin', login)
    }
    
    // 在此处完成网络请求就可以了
    // generator的返回值,不是普通函数这样的返回值,这样在登录成功后,无法让前端的组件完成路由的切换,
    // 切换的原则是登录成功后,才能能跳转,登录的过程它是一个异步的,所以此时工作就有点难受,所以需要用到库
    function* login({ payload }) {
      // call内部实现了 co 方法,可以将自己的返回值返回给 ret
      let ret = yield call(loginApi, payload)
      // 得到的数据同步到redux中
      if (ret.code === 0) {
        // 通过reducer完成redux中的数据更新  登录成功
        yield put({ type: 'userLogin', payload: ret.data })
        // 跳转到后台首页 -- 在redux中间件中就可以完成路由的跳转
        yield put(push('/'))
      }
    }
    
  6. 在前台页面不用使用 hack 方式,而是使用当前库实现路由跳转:

    import React from 'react'
    // react-redux提供的hook工具函数
    import { useDispatch, useSelector } from 'react-redux'
    
    const Login = ({ history }) => {
      const dispatch = useDispatch()
      let num = useSelector(state => state.count.num)
    
      const doLogin = () => {
        // 进行登录,它是一个异步的,交给saga,saga会完成异步操作,通知reducer完成同步修改redux中的state数据改变
        // reducer把state中的数据修改后,因为我在当前的组件中有通过useEffect来依赖此state中的值的变化,所以它只要变化了,我就可以来跳转,从而可以确认redux中的数据一定是存在后才跳转的
        dispatch({ type: 'asyncLogin', payload: { username: 'admin', password: 'admin888' } })
      }
    
      return (
        <div>
          <h3>
            {num}
          </h3>
          <button onClick={doLogin}>进入系统</button>
        </div>
      )
    }
    
    export default Login
    

React中的redux-saga详解文章来源地址https://www.toymoban.com/news/detail-444440.html

到了这里,关于React中的redux-saga详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • react中使用redux,但是通过useEffect监听不到redux中的数据变化?

    在React中使用Redux并通过useEffect监听Redux中的数据变化时,需要使用 react-redux 库中的 useSelector 钩子来选择需要监听的Redux状态。 useSelector 函数允许您从Redux存储中选择和获取特定的状态。 以下是一种在React组件中使用Redux,并通过useEffect监听Redux中的数据变化的常见方法: 首先

    2024年02月16日
    浏览(49)
  • React - Redux Hooks的使用细节详解

    Redux中Hooks介绍 在之前的redux开发中,为了让组件和redux结合起来,我们使用了react-redux库中的connect : 但是这种方式必须使用高阶函数结合返回的高阶组件; 并且必须编写:mapStateToProps和 mapDispatchToProps映射的函数, 具体使用方式在前面文章有讲解; 在Redux7.1开始,提供了Hook的方式

    2024年02月02日
    浏览(51)
  • react中的redux的了解,三大核心理念以及三大原则

    1、要学习redux首先我们先了解下函数式编程中的纯函数;我们最基本的javascript符合函数式编程,因此他也有纯函数。 纯函数:在程序中,若一个函数复合下面的条件,那么这个函数就可以被称为纯函数: ⑴这个函数在相同输入值时,需产生相同的输出。纯函数的输出和输入

    2023年04月08日
    浏览(36)
  • 【前端知识】React 基础巩固(三十三)——Redux的使用详解

    针对 React 基础巩固(三十二) 中的案例,我们希望抽取页面中共有的代码(例如下方的代码),使用高阶组件统一拦截。 为了让react和redux产生联系,安装一款工具 react-redux 使用 react-redux ,在index.js中统一注入store 新建about.js页面,通过 react-redux 引入store 在App.jsx中引入新的

    2024年02月15日
    浏览(52)
  • react之react-redux的介绍、基本使用、获取状态、分发动作、数据流、reducer的分离与合并等

    官网地址 React 和 Redux 是两个独立的库,两者之间职责独立。因此,为了实现在 React 中使用 Redux 进行状态管理 ,就需要一种机制,将这两个独立的库关联在一起。这时候就用到 React-Redux 这个绑定库了 作用:为 React 接入 Redux,实现在 React 中使用 Redux 进行状态管理。 react-r

    2024年02月11日
    浏览(54)
  • React中使用Redux (二) - 通过react-redux库连接React和Redux

    react-redux库使用Redux 上一篇文章演示React中直接使用Redux的使用过程是十分繁琐的, 并且有许多重复代码 但是实际上redux官方帮助我们提供了 react-redux 的库,这个库是帮助我们完成连接redux和react的辅助工具, 可以直接在项目中使用,并且实现的逻辑会更加的严谨和高效 这篇我们

    2024年02月20日
    浏览(53)
  • 【React】redux和React-redux

    🎀个人主页:努力学习前端知识的小羊 感谢你们的支持:收藏🎄 点赞🍬 加关注🪐 redux 适用于多交互、多数据源的场景。 使用redux的场景: 某个组件的状态需要共享 一个组件需要改变其他组件的状态时 一个组件需要改变全局的状态时 redux的三大原则: 整个应用的 state

    2024年02月06日
    浏览(57)
  • React中使用Redux (一) - 在React中直接使用Redux

    开始之前需要强调一下,redux和react没有直接的关系,你完全可以在React, Angular, Ember, jQuery, or vanilla JavaScript中使用Redux 。 尽管这样说,redux依然是和React库结合的更好,因为他们是通过state函数来描述界面的状态,Redux可以发射状态的更新, 让他们作出相应; 目前redux在react中使

    2024年01月23日
    浏览(59)
  • 在react中使用redux && react-redux的使用demo

    前言: redux是一种状态管理工具,可以存储和操作一些全局或者很多组件需要使用的公共数据。 平心而论,redux的使用对于新上手来说不太友好,多个依赖包的,多种api的结合使用,相对来说比做同样一件事的vuex用起来比较麻烦.不过,熟能生巧,用多了也就习惯了,下面是个人的一个d

    2024年02月06日
    浏览(55)
  • 【React】React——redux

    🚩🚩🚩 💎个人主页: 阿选不出来 💨💨💨 💎个人简介: 一名大二在校生,学习方向前端,不定时更新自己学习道路上的一些笔记. 💨💨💨 💎目前开发的专栏: JS 🍭Vue🍭React🍭 💨💨💨 Redux 是 JavaScript 状态容器,提供可预测化的状态管理。 redux是什么 redux是一个专门用于

    2024年01月15日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包