详解如何优雅地在React项目中使用Redux


Posted in Javascript onDecember 28, 2017

前言

或许你当前的项目还没有到应用Redux的程度,但提前了解一下也没有坏处,本文不会安利大家使用Redux

概念

首先我们会用到哪些框架和工具呢?

React

UI框架

Redux

状态管理工具,与React没有任何关系,其他UI框架也可以使用Redux

react-redux

React插件,作用:方便在React项目中使用Redux

react-thunk

中间件,作用:支持异步action

目录结构

Tips:与Redux无关的目录已省略

|--src
 |-- store     Redux目录
  |-- actions.js
  |-- index.js
  |-- reducers.js
  |-- state.js
 |-- components  组件目录
  |-- Test.jsx
 |-- App.js    项目入口

准备工作

第1步:提供默认值,既然用Redux来管理数据,那么数据就一定要有默认值,所以我们将state的默认值统一放置在state.js文件

// state.js
// 声明默认值
// 这里我们列举两个示例
// 同步数据:pageTitle
// 异步数据:infoList(将来用异步接口获取)
export default {
 pageTitle: '首页',
 infoList: []
}

第2步:创建reducer,它就是将来真正要用到的数据,我们将其统一放置在reducers.js文件

// reducers.js
// 工具函数,用于组织多个reducer,并返回reducer集合
import { combineReducers } from 'redux'
// 默认值
import defaultState from './state.js'

// 一个reducer就是一个函数
function pageTitle (state = defaultState.pageTitle, action) {
 // 不同的action有不同的处理逻辑
 switch (action.type) {
 case 'SET_PAGE_TITLE':
  return action.data
 default:
  return state
 }
}

function infoList (state = defaultState.infoList, action) {
 switch (action.type) {
 case 'SET_INFO_LIST':
  return action.data
 default:
  return state
 }
}

// 导出所有reducer
export default combineReducers({
 pageTitle,
 infoList
})

第3步:创建action,现在我们已经创建了reducer,但是还没有对应的action来操作它们,所以接下来就来编写action

// actions.js
// action也是函数
export function setPageTitle (data) {
 return (dispatch, getState) => {
 dispatch({ type: 'SET_PAGE_TITLE', data: data })
 }
}

export function setInfoList (data) {
 return (dispatch, getState) => {
 // 使用fetch实现异步请求
 window.fetch('/api/getInfoList', {
  method: 'GET',
  headers: {
   'Content-Type': 'application/json'
  }
 }).then(res => {
  return res.json()
 }).then(data => {
  let { code, data } = data
  if (code === 0) {
   dispatch({ type: 'SET_INFO_LIST', data: data })
  }
 })
 }
}

最后一步:创建store实例

// index.js
// applyMiddleware: redux通过该函数来使用中间件
// createStore: 用于创建store实例
import { applyMiddleware, createStore } from 'redux'

// 中间件,作用:如果不使用该中间件,当我们dispatch一个action时,需要给dispatch函数传入action对象;但如果我们使用了这个中间件,那么就可以传入一个函数,这个函数接收两个参数:dispatch和getState。这个dispatch可以在将来的异步请求完成后使用,对于异步action很有用
import thunk from 'redux-thunk'

// 引入reducer
import reducers from './reducers.js'

// 创建store实例
let store = createStore(
 reducers,
 applyMiddleware(thunk)
)
export default store

至此,我们已经完成了所有使用Redux的准备工作,接下来就在React组件中使用Redux

开始使用

首先,我们来编写应用的入口文件APP.js

import React from 'react'
import ReactDOM from 'react-dom'
// 引入组件
import TestComponent from './components/Test.jsx'

// Provider是react-redux两个核心工具之一,作用:将store传递到每个项目中的组件中
// 第二个工具是connect,稍后会作介绍
import { Provider } from 'react-redux'
// 引入创建好的store实例
import store from '@/store/index.js'

// 渲染DOM
ReactDOM.render (
 (
 <div>
  {/* 将store作为prop传入,即可使应用中的所有组件使用store */}
  <Provider store = {store}>
   <TestComponent />
  </Provider>
 </div>
 ),
 document.getElementById('root')
)

最后是我们的组件:Test.jsx

// Test.jsx
import React, { Component } from 'react'

// connect方法的作用:将额外的props传递给组件,并返回新的组件,组件在该过程中不会受到影响
import { connect } from 'react-redux'

// 引入action
import { setPageTitle, setInfoList } from '../store/actions.js'
class Test extends Component {
 constructor(props) {
 super(props)
 }
 componentDidMount () {
 let { setPageTitle, setInfoList } = this.props
 
 // 触发setPageTitle action
 setPageTitle('新的标题')
 
 // 触发setInfoList action
 setInfoList()
 }

 render () {
 // 从props中解构store
 let { pageTitle, infoList } = this.props
 
 // 使用store
 return (
  <div>
  <h1>{pageTitle}</h1>
  {
   infoList.length > 0 ? (
    <ul>
     {
      infoList.map((item, index) => {
       <li>{item.data}</li>
      })
     }
    </ul>
   ):null
  }
  </div>
 )
 }
}

// mapStateToProps:将state映射到组件的props中
const mapStateToProps = (state) => {
 return {
 pageTitle: state.pageTitle,
 infoList: state.infoList
 }
}

// mapDispatchToProps:将dispatch映射到组件的props中
const mapDispatchToProps = (dispatch, ownProps) => {
 return {
 setPageTitle (data) {
  // 如果不懂这里的逻辑可查看前面对redux-thunk的介绍
  dispatch(setPageTitle(data))
  // 执行setPageTitle会返回一个函数
  // 这正是redux-thunk的所用之处:异步action
  // 上行代码相当于
  /*dispatch((dispatch, getState) => {
   dispatch({ type: 'SET_PAGE_TITLE', data: data })
  )*/
 },
 setInfoList (data) {
  dispatch(setInfoList(data))
 }
 }
}
export default connect(mapStateToProps, mapDispatchToProps)(Test)

Redux三大原则

1、单一数据源

整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中

2、State 是只读的

唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象

3、使用纯函数来执行修改

为了描述 action 如何改变 state tree ,你需要编写 reducers

结语

以上就是在React项目中使用Redux的简单示例,文中代码可能会有编写错误,欢迎指正,同时希望本文对大家有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
不错的asp中显示新闻的功能
Oct 13 Javascript
一句话JavaScript表单验证代码
Aug 02 Javascript
JQuery一种取同级值的方式(比如你在GridView中)
Mar 15 Javascript
jQuery中animate用法实例分析
Mar 09 Javascript
举例讲解JavaScript中将数组元素转换为字符串的方法
Oct 25 Javascript
jquery 实现复选框的全选操作实例代码
Jan 24 Javascript
如何编写jquery插件
Mar 29 jQuery
微信小程序js文件改变参数并在视图上及时更新【推荐】
Jun 11 Javascript
vue集成百度UEditor富文本编辑器使用教程
Sep 21 Javascript
vue router 用户登陆功能的实例代码
Apr 24 Javascript
vue 封装面包屑组件教程
Nov 16 Javascript
Vue2.x-使用防抖以及节流的示例
Mar 02 Vue.js
ionic3实战教程之随机布局瀑布流的实现方法
Dec 28 #Javascript
JS实现带动画的回到顶部效果
Dec 28 #Javascript
JavaScript实现元素滚动条到达一定位置循环追加内容
Dec 28 #Javascript
在nginx上部署vue项目(history模式)的方法
Dec 28 #Javascript
js实现把时间戳转换为yyyy-MM-dd hh:mm 格式(es6语法)
Dec 28 #Javascript
vue获取dom元素注意事项
Dec 28 #Javascript
vue实现文章内容过长点击阅读全文功能的实例
Dec 28 #Javascript
You might like
php输出表格的实现代码(修正版)
2010/12/29 PHP
PHP遍历二维数组的代码
2011/04/22 PHP
浏览器关闭后,能继续执行的php函数(ignore_user_abort)
2012/08/01 PHP
PHP中SESSION的注销与清除
2015/04/16 PHP
PHP中Closure类的使用方法及详解
2015/10/09 PHP
PHP共享内存用法实例分析
2016/02/12 PHP
PHP中file_exists使用中遇到的问题小结
2016/04/05 PHP
javascript 自动填写表单的实现方法
2010/04/09 Javascript
jquery实现从数组移除指定的值
2015/06/24 Javascript
JavaScript lodash常见用法系列小结
2016/08/24 Javascript
jQuery判断是否存在滚动条的简单方法
2016/09/17 Javascript
windows下vue-cli及webpack搭建安装环境
2017/04/25 Javascript
js实现鼠标拖拽多选功能示例
2017/08/01 Javascript
jQuery实现IE输入框完成placeholder标签功能的方法
2017/09/20 jQuery
JavaScript实现仿Clock ISO时钟
2018/06/29 Javascript
Angular6中使用Swiper的方法示例
2018/07/09 Javascript
基于nodejs的雪碧图制作工具的示例代码
2018/11/05 NodeJs
详解如何在Vue项目中导出Excel
2019/04/19 Javascript
JS继承实现方法及优缺点详解
2020/09/02 Javascript
Python中表达式x += y和x = x+y 的区别详解
2017/06/20 Python
24式加速你的Python(小结)
2019/06/13 Python
Python3的socket使用方法详解
2020/02/18 Python
解决H5的a标签的download属性下载service上的文件出现跨域问题
2019/07/16 HTML / CSS
Sarenza德国:法国最大的时尚鞋和包包网上商店
2019/06/08 全球购物
澳大利亚排名第一的露营和户外设备在线零售商:Outbax
2020/05/06 全球购物
关于Assembly命名空间的三个面试题
2015/07/23 面试题
送给程序员的20个Java集合面试问题
2014/08/06 面试题
大学生大二自我鉴定
2013/10/28 职场文书
电气工程和自动化自荐信范文
2013/12/25 职场文书
投标承诺书范本
2014/03/27 职场文书
党员创先争优心得体会
2014/09/11 职场文书
小学四年级学生评语
2014/12/26 职场文书
中学生自我评价范文
2015/03/03 职场文书
培养联系人考察意见
2015/06/01 职场文书
oracle连接ODBC sqlserver数据源的详细步骤
2021/07/25 Oracle
Python加密技术之RSA加密解密的实现
2022/04/08 Python