React之redux学习日志(redux/react-redux/redux-saga)

React之redux学习日志(redux/react-redux/redux-saga)

redux官方中文文档:https://www.redux.org.cn/docs/introduction/CoreConcepts.html

react-redux Dome:https://codesandbox.io/s/react-redux-e1el3(需翻墙才能访问)

1. Redux工作流程图:

<span>React之redux学习日志(redux/react-redux/redux-saga)</span>

 

2. redux三大原则:

  1. 单一数据源:在Redux中有且只能有一个 state 仓库

  2. State是只读的: state仓库的数据只能读取,不能进行修改

  3. 使用纯函数执行修改:reducer中,应该返回一个纯函数,函数接受先前的 state和action, 然后返回一个新的 state

 

3. Redux 搭配 React 使用

安装:

npm install --save react-redux

      3.1. react-redux在React中的使用方式

  · 在react入口文件中注入Redux

import React from 'react'
import ReactDOM from 'react-dom'
import RouterConfig from '@/Router'
import { Provider } from 'react-redux'
import store from '@/store'

const App = () => (
  <div>
   <!-- Provider 让所有容器组件都可以访问 store -->
    <Provider store={store}>
      <RouterConfig/>  
    </Provider>
  </div>
)

const domContainer = document.querySelector('#app')
ReactDOM.render(<App />, domContainer)

  · 根目录中新建store目录,并且添加:index.js、 reducer.js、create-action、action-type

       <span>React之redux学习日志(redux/react-redux/redux-saga)</span>

  index.js文件

import 'babel-polyfill' // es6解析
import {
  createStore,
  compose,
  applyMiddleware
} from 'redux'
import reducer from './reducer'


// redux-dev-tools工具配置
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose

const store = createStore(
  reducer,
  composeEnhancers(
    applyMiddleware(
    // 这里可以放一些中间件,如 redux-saga 等
    )
  )
)

export default store

  create-action.js  / action-type.js

// action-type: 一般统一在这个文件中定义 action 的类型,方便管理
export const GET_USERINFO_ACTION = 'GET_USERINFO_ACTION'

// create-action:每个action都返回一个纯对象,type是约定必须
import { GET_USERINFO_ACTION  } from './action-type'
export const getUserInfoAction = (value) => ({
    type: GET_USERINFO_ACTION,
    value
})

  reducer.js

import { GET_USERINFO_ACTION  } from './action-type'
// 创建一个默认的仓库,一般提出来会更加清晰
const defaultState = { userInfo: {} }
// reducer必须是一个纯函数 const reducer = (state=defaultState, action) => { const { type } = action
// 深拷贝,一定不能直接对state进行修改 const newState = JSON.parse(JSON.stringify(state)) if (type === GET_USERINFO_ACTION){ newState.userInfo = action.value } return newState }  

至此,仓库已经搭建完毕,接下来是在react中进行使用。

上面已经在react中入口文件中注入了react,接下创建一个组件来对redux进行简单的使用

新建 ReduxTest 组件

import React, { Component, Fragment } from "react";
import stroe from "./stroe";
import { getUserInfoAction} from "./stroe/action-creators";

class TestRedux extends Component {
  constructor(props) {
    super(props)

    this.handleUpdateUserInfoClick = this.handleUpdateUserInfoClick.bind(this)
  }

  handleUpdateUserInfoClick() {
// 创建一个action,然后reducer会进行对于的处理,然后返回一个新的 state const action = getUserInfoAction({name: 'del lee'}) stroe.dispatch(action) } render() { return ( <Fragment> <button onClick={this.handleUpdateUserInfoClick}>跳转</button> </Fragment> ) } } export default TestRedux

  

 4. react-redux 在react中的使用

  结合上面的内容,我们修改一下ReduxTest组件

import React, { Component, Fragment } from "react";
import stroe from "./stroe";
import { getUserInfoAction} from "./stroe/action-creators";

// 引入 connect
import { connect } from "react-redux";

class TestRedux extends Component {
  constructor(props) {
    super(props)

    // this.handleUpdateUserInfoClick = this.handleUpdateUserInfoClick.bind(this)
  }

  // handleUpdateUserInfoClick() {
  //   创建一个action,然后reducer会进行对于的处理,然后返回一个新的 state
  //   const action = getUserInfoAction({name: 'del lee'})
  //   stroe.dispatch(action)
  //}

  render() {
    return (
      <Fragment>
<!--      <button onClick={this.handleUpdateUserInfoClick}>跳转</button> -->

      <button onClick={this.props.handleUpdateUserInfoClick}>跳转</button>
      </Fragment>
    )
  }
}

const mapStateToProps = state => ({
   userInfo: state.userInfo
})

const mapDispatchToProps = (dispatch) => ({
   handleUpdateUserInfoClick: ()=> {
        const action = getUserInfoAction({name: 'del lee'})
        dispatch(action) // 执行action
   }
})


// export default TestRedux

// 修改为,connect会将 mapStateToProps 与 mapDispatchToProps中的内容链接到 TestRedux 组件的props中
// mapStateToProps 会接受到 state 仓库中所有的值
// mapDispatchToProps: 会接受到 dispatch 方法
export default connect(mapStateToProps, mapDispatchToProps)(TestRedux )    

 

备注:为了确保redux中的state不能够直接修改其中的值和统一数据格式,一般建议结合  immutable.js 使用

           具体需查阅官方文档:https://immutable-js.github.io/immutable-js/docs/#/

示例: 修改 reducer.js 文件

import { GET_USERINFO_ACTION  } from './action-type'
import { fromJS } from "immutable";

// 创建一个默认的仓库,一般提出来会更加清晰
//const defaultState = {
//  userInfo: {}
//}

// 转换为 immutable 数据格式
const defaultState = fromJS({
  userInfo: {}
})

// reducer必须是一个纯函数
const reducer = (state=defaultState, action) => {
   const { type } = action
   // 深拷贝,一定不能直接对state进行修改
   // const newState = JSON.parse(JSON.stringify(state))  immutable数据格式不需要进行深拷贝
   
   if (type === GET_USERINFO_ACTION){
      // newState.userInfo = action.value  不能直接修改值
      // 使用set方法对值进行修改,会返回一个新的immutable对象
      state.set('userInfo', action.value)
   }
   
   return state  // 若不匹配直接返回原来的state即可
   // return newState
}  

  还需要修改 ReduxTest 中 mapStateToProps 的获取方式

......

const mapStateToProps = state => ({
// userInfo: state.userInfo 会抛出异常
// 使用get或者getIn获取state中的值 userInfo: state.get('userInfo') // or // userInfo: state.getIn(['userInfo']) }) ......

  
5. Redux-Saga中间件

redux-saga中文文档地址:https://redux-saga-in-chinese.js.org/docs/basics/DeclarativeEffects.html

当我们需要执行一些异步操作时,由于action中只能返回一个对象,从而需要借助一些中间件来达到目的,redux-thunk 和 redux-saga是常见的两种中间件。

<span>React之redux学习日志(redux/react-redux/redux-saga)</span>

  redux-thunk 主要是使action能够返回一个函数而达到目的,这样导致了action函数变得复杂

  redux-saga 可以将异步操作单独分离出来封装到某些模块,这样保证action函数更加干净

 

 

 

redux-saga的引入:

  修改 store/index.js 文件

import 'babel-polyfill' // es6解析
import {
  createStore,
  compose,
  applyMiddleware
} from 'redux'
import reducer from './reducer'

// 需要在 store 目录中创建  sagas.js 文件
import testSaga from "./sagas";
import createSagaMiddleware from "redux-saga";

// 创建 redux-saga 中间件
const sagaMiddleware = createSagaMiddleware();

// redux-dev-tools工具配置
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose

const store = createStore(
  reducer,
  composeEnhancers(
    applyMiddleware(
        sagaMiddleware // 引入saga中间件
    )
  )
)

// 运行saga
sagaMiddleware.run(testSaga)

export default store        

  在 store 中新增 sagas.js 文件

import { call, put, takeEvery } from "redux-saga/effects"
// 你可以写一个异步的接口或者一个异步的函数
import { getUserInfoApi } from './api'
// 可以在create-action.js中新增一个 action:   updateUserInfoAction
import { updateUserInfoAction } from 'create-action'

/** 在create-action.js新增一个action(当然在reducer.js中也要对state就行对应的操作)
* export const updateUserInfoAction = (value) => ({
*  type: 'UPDATE_USERINFO_ACTION',
*  value
*})
*/
// saga 函数接受 action
function* getUserInfoSaga(action) {
    // 声明 effects 函数 call:发起一次请求   call([api, [args]]),args是请求的参数
    const res = yield call(getUserInfoApi, action.userId)
    
   // 声明 effects 函数 put: 相当于 store中的dispatch
  put(updateUserInfoAction(res))
}
function* testSaga() {
   // 当action-type被准备dispatch时,执行 getUserInfo
   // 声明 effects 函数:takeEvery 监听一个action
    yield takeEvery('GET_USERINFO_ACTION', getUserInfoSaga)
}

export default testSaga

  

  这样就完成了一个简单的redux-saga的配置和使用,在component中dispatch getUserInfoAction这个action,就会执行 getUserInfoSaga 函数,这样就完成了异步的拓展。

  redux-saga中有很多 声明 effects 函数(比如:call、put、takeEvery、all、fock等等),具体请查阅redux-saga文档。

备注:redux-saga函数必须是一个Generator函数

 

拓展:还可以通过以下代码来将saga进行模块化:

import { all, fork } from 'redux-saga/effects'
// 以下saga是我个人项目中使用到的
import headNavigationBarSagas from '@/commponents/HeadNavigationBar/store/sagas'
import viewsHomeSagas from '@/views/Home/store/sagas'
import viewsDetailSagas from '@/views/Detail/store/sagas'
import viewsLoginSagas from '@/views/Login/store/sagas'
import backstageArticleManage from '@/views/backstage/ArticleManage/store/sagas'

// 整合多个模块的saga
export default function * rootSaga () {
  yield all([
    fork(headNavigationBarSagas),
    fork(viewsHomeSagas),
    fork(viewsDetailSagas),
    fork(viewsLoginSagas),
    fork(backstageArticleManage)
  ])
}

  

大致介绍了redux、react-redux的基本用法和redux-saga中间件的使用,若有错误请各路大佬指出加以改正和学习

 

——

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/2587.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 怎样开挂的教程_销售常见的八个问题

    怎样开挂的教程_销售常见的八个问题概念篇1、什么是外挂它是怎样定义?外挂是指某些人利用自己的电脑技术专门针对一个或多个网络游戏,通过改变网络游戏软件的部分程序,制作而成的作弊程序。这是一个让游戏公司痛恨、玩家分派、作者成就、工作室必备的游戏辅助软件程序。2、一般外挂分几类?有模拟类、内存类、封包类、变态类、脱机类,一般来讲模拟类是最轻的,比如用按键精灵来代替鼠标和键盘的操作;内存挂、封包挂是比较正规和普遍的

    2022年10月31日
  • C# 发送Http请求 – WebClient类

    WebClient位于System.Net命名空间下,通过这个类可以方便的创建Http请求并获取返回内容。一、用法1- DownloadData二、用法2- OpenRea

    2021年12月27日
  • 做了三年Java,java注释的三种形式

    做了三年Java,java注释的三种形式前言很多同学想进大厂,特别是刚毕业的,以及工作年限短的,不要有任何侥幸心理,踏踏实实的把基础弄扎实了,这是你通往高薪之路的唯一正确姿势。首先从面试题做起~好了,不多说了,直接上正菜。拼多多一面首先自我介绍参加过哪些项目并发编程三要素?实现可见性的方法有哪些?多线程的价值?创建线程的三种方式的对比?画出线程的状态流转图常用的并发工具类有哪些?CyclicBarrier和CountDownLatch的区别CAS的问题:1、CAS容易造成ABA问题2、不能保证代码块的原子

  • 开心网买房子外挂_开心躲猫猫穿墙版下载

    开心网买房子外挂_开心躲猫猫穿墙版下载     开心网的买房子组件出了很久了,竟然到现在还没有出一个买房外挂。上星期某一晚上基于turbozv.com提供的抢车位的源代码,改写了一个买房子的外挂,此外挂不具有抢人住自己家的功能,那个不赚钱。来钱最快的是每隔一小时换一个地方住,随机得0到6000之前的住房津贴。经过一个星期的尝试,平均每天入帐5万,嘿嘿。发给大家一起来挂吧,祝大家早日住上大别墅。…

  • mysql list table_java resultset转list

    mysql list table_java resultset转list我在Orcle里写了一个Sql语句,用到了LISTAGG,现在要改成mysql数据库,我要怎么改这个Sql语句?SELECTA.GUID,A.COMPANY_GUID,A.GOODS_CODE,A.GOODS_NAME,A.SPECIFICATIONS,A.SMALL_IM…我在Orcle里写了一个Sql语句,用到了LISTAGG,现在要改成mysql数据库,我要怎么改这个Sql语句?SELE…

  • thinkphp无法加载控制器:Admin

    thinkphp无法加载控制器:Admin

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号