优雅的在React项目中使用Redux的方法


Posted in Javascript onNovember 10, 2018

或许你当前的项目还没有到应用Redux的程度,但提前了解一下也没有坏处

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

React
UI框架
Redux
状态管理工具,与React没有任何关系,其他UI框架也可以使用Redux
react-redux
React插件,作用:方便在React项目中使用Redux
react-thunk
中间件,作用:支持异步action

|--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

// 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三大原则

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

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

使用纯函数来执行修改
为了描述 action 如何改变 state tree ,你需要编写 reducers

结语

感谢您的观看,以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
通过判断JavaScript的版本实现执行不同的代码
May 11 Javascript
jQuery的缓存机制浅析
Jun 07 Javascript
分享2个jQuery插件--jquery.fileupload与artdialog
Dec 26 Javascript
基于JSON格式数据的简单jQuery幻灯片插件(jquery-slider)
Aug 10 Javascript
js点击时关闭该范围下拉菜单之外的菜单方法
Jan 11 Javascript
基于jQuery实现无缝轮播与左右点击效果
May 13 jQuery
JS实现的判断方法、变量是否存在功能示例
Mar 28 Javascript
微信小程序实现的绘制table表格功能示例
Apr 26 Javascript
JS代码检查工具ESLint介绍与使用方法
Feb 04 Javascript
有趣的JavaScript隐式类型转换操作实例分析
May 02 Javascript
基于js实现数组相邻元素上移下移
May 19 Javascript
微信小程序点击生成朋友圈分享图(遇到的坑)
Jun 17 Javascript
Vue组件之单向数据流的解决方法
Nov 10 #Javascript
详解如何制作并发布一个vue的组件的npm包
Nov 10 #Javascript
如何在基于vue-cli的项目自定义打包环境
Nov 10 #Javascript
Vue项目报错:Uncaught SyntaxError: Unexpected token
Nov 10 #Javascript
node+express框架中连接使用mysql(经验总结)
Nov 10 #Javascript
vue axios请求频繁时取消上一次请求的方法
Nov 10 #Javascript
微信小程序实现跑马灯效果
Oct 21 #Javascript
You might like
PHPMailer 中文使用说明小结
2010/01/22 PHP
让你成为更出色的PHP开发者的10个技巧
2011/02/25 PHP
PHP实现简单的新闻发布系统实例
2015/07/28 PHP
PHP实现根据数组某个键值大小进行排序的方法
2018/03/13 PHP
Yii2语言国际化的配置教程
2018/08/19 PHP
jquery 批量上传图片实现代码
2010/01/28 Javascript
MC Dialog js弹出层 完美兼容多浏览器(5.6更新)
2010/05/06 Javascript
JavaScript判断一个URL链接是否有效的实现方法
2011/10/08 Javascript
js setTimeout 参数传递使用介绍
2013/08/13 Javascript
javascript实现点击按钮让DIV层弹性移动的方法
2015/02/24 Javascript
jquery实现鼠标滑过显示二级下拉菜单效果
2015/08/24 Javascript
Node.js的Web模板引擎ejs的入门使用教程
2016/06/06 Javascript
jQuery 3.0中存在问题及解决办法
2016/07/15 Javascript
Bootstrap table简单使用总结
2017/02/15 Javascript
vue-cli的webpack模板项目配置文件分析
2017/04/01 Javascript
ES6中的rest参数与扩展运算符详解
2017/07/18 Javascript
微信小程序 POST请求的实例详解
2017/09/29 Javascript
Vue的实例、生命周期与Vue脚手架(vue-cli)实例详解
2017/12/27 Javascript
Angular通过指令动态添加组件问题
2018/07/09 Javascript
详解三种方式解决vue中v-html元素中标签样式
2018/11/22 Javascript
[00:34]TI7不朽珍藏III——纯金地穴编织者饰品展示
2017/07/15 DOTA
[01:39:42]Fnatic vs Mineski 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
python写的一个文本编辑器
2014/01/23 Python
Python中使用partial改变方法默认参数实例
2015/04/28 Python
尝试用最短的Python代码来实现服务器和代理服务器
2016/06/23 Python
详解Python核心编程中的浅拷贝与深拷贝
2018/01/07 Python
numpy.where() 用法详解
2019/05/27 Python
django2笔记之路由path语法的实现
2019/07/17 Python
Python变量作用域LEGB用法解析
2020/02/04 Python
CSS3旋转——彩色扇子兼容firefox浏览器
2013/06/04 HTML / CSS
详解CSS3原生支持div铺满浏览器的方法
2018/08/30 HTML / CSS
HTML5中的Article和Section元素认识及使用
2013/03/22 HTML / CSS
学生会竞选自荐信
2013/10/12 职场文书
个人债务授权委托书范本
2014/10/05 职场文书
外贸采购员岗位职责
2015/04/03 职场文书
2016年“11.11”光棍节活动总结
2016/04/05 职场文书