react+redux教程(一)connect、applyMiddleware、thunk、webpackHotMiddleware

本文主要是介绍react+redux教程(一)connect、applyMiddleware、thunk、webpackHotMiddleware,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天,我们通过解读官方示例代码(counter)的方式来学习react+redux。

例子

这个例子是官方的例子,计数器程序。前两个按钮是加减,第三个是如果当前数字是奇数则加一,第四个按钮是异步加一(延迟一秒)。

源代码:https://github.com/lewis617/react-redux-tutorial/tree/master/redux-examples/counter

组件
components/Counter.js

import React, { Component, PropTypes } from 'react'class Counter extends Component {render() {//从组件的props属性中导入四个方法和一个变量const { increment, incrementIfOdd, incrementAsync, decrement, counter } = this.props;//渲染组件,包括一个数字,四个按钮return (<p>Clicked: {counter} times{' '}<button onClick={increment}>+</button>{' '}<button onClick={decrement}>-</button>{' '}<button onClick={incrementIfOdd}>Increment if odd</button>{' '}<button onClick={() => incrementAsync()}>Increment async</button></p>)}
}
//限制组件的props安全
Counter.propTypes = {//increment必须为fucntion,且必须存在increment: PropTypes.func.isRequired,incrementIfOdd: PropTypes.func.isRequired,incrementAsync: PropTypes.func.isRequired,decrement: PropTypes.func.isRequired,//counter必须为数字,且必须存在counter: PropTypes.number.isRequired
};export default Counter

上述代码,我们干了几件事:

从props中导入变量和方法
渲染组件
有的同学可能会急于想知道props的方法和变量是怎么来,下面我们继续解读。

容器
containers/App.js

import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import Counter from '../components/Counter'
import * as CounterActions from '../actions/counter'

//将state.counter绑定到props的counter
function mapStateToProps(state) {return {counter: state.counter}
}
//将action的所有方法绑定到props上
function mapDispatchToProps(dispatch) {return bindActionCreators(CounterActions, dispatch)
}

//通过react-redux提供的connect方法将我们需要的state中的数据和actions中的方法绑定到props上
export default connect(mapStateToProps, mapDispatchToProps)(Counter)

看到这里,很多刚接触redux同学可能已经晕了,我来图解下redux的流程。

state就是数据,组件就是数据的呈现形式,action是动作,action是通过reducer来更新state的。

上述代码,我们干了几件事:

把state的counter值绑定到props上
把四个action创建函数绑定到props上
connect
那么为什么就绑定上去了呢?因为有connect这个方法。这个方法是如何实现的,或者我们该怎么用这个方法呢?connect这个方法的用法,可以直接看api文档。我也可以简单描述一下:

第一个参数,必须是function,作用是绑定state的指定值到props上面。这里绑定的是counter
第二个参数,可以是function,也可以是对象,作用是绑定action创建函数到props上。
返回值,是绑定后的组件
这里还有很多种其他写法,我喜欢在第二个参数绑定一个对象,即

import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import Counter from '../components/Counter'
import * as CounterActions from '../actions/counter'//将state.counter绑定到props的counter
function mapStateToProps(state) {return {counter: state.counter}
}//通过react-redux提供的connect方法将我们需要的state中的数据和actions中的方法绑定到props上
export default connect(mapStateToProps, CounterActions)(Counter)

还可以不写第二个参数,后面用dispatch来触发action的方法,即

import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import Counter from '../components/Counter'
import * as CounterActions from '../actions/counter'//将state.counter绑定到props的counter
function mapStateToProps(state) {return {counter: state.counter}
}//通过react-redux提供的connect方法将我们需要的state中的数据绑定到props上
export default connect(mapStateToProps)(Counter)

后面在组件中直接使用dispatch()来触发action创建函数。

action和reducer两个好基友负责更新state
actions/counter.js

export const INCREMENT_COUNTER = 'INCREMENT_COUNTER'
export const DECREMENT_COUNTER = 'DECREMENT_COUNTER'
//导出加一的方法
export function increment() {return {type: INCREMENT_COUNTER}
}
//导出减一的方法
export function decrement() {return {type: DECREMENT_COUNTER}
}
//导出奇数加一的方法,该方法返回一个方法,包含dispatch和getState两个参数,dispatch用于执行action的方法,getState返回state
export function incrementIfOdd() {return (dispatch, getState) => {//获取state对象中的counter属性值const { counter } = getState()//偶数则返回if (counter % 2 === 0) {return}//没有返回就执行加一dispatch(increment())}
}
//导出一个方法,包含一个默认参数delay,返回一个方法,一秒后加一
export function incrementAsync(delay = 1000) {return dispatch => {setTimeout(() => {dispatch(increment())}, delay)}
}//这些方法都导出,在其他文件导入时候,使用import * as actions 就可以生成一个actions对象包含所有的export

reducers/counter.js

import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../actions/counter'//reducer其实也是个方法而已,参数是state和action,返回值是新的state
export default function counter(state = 0, action) {switch (action.type) {case INCREMENT_COUNTER:return state + 1case DECREMENT_COUNTER:return state - 1default:return state}
}

reducers/index.js

import { combineReducers } from 'redux'
import counter from './counter'//使用redux的combineReducers方法将所有reducer打包起来
const rootReducer = combineReducers({counter
})export default rootReducer

上述代码我们干了几件事:

写了四个action创建函数
写了reducer用于更新state
将所有reducer(这里只有一个)打包成一个reducer
看到这里,有很多初次接触redux的同学可能已经晕了,怎么那么多概念?为了形象直观,我们在开发工具(react dev tools)上看看这些state,props什么的:

action的方法和state的变量是不是都绑定上去了啊。state怎么看呢?这个需要借助redux的开发工具,也可以通过Connect(Counter)组件的State来查看redux那颗全局唯一的状态树:

那个storeState就是全局唯一的状态树。我们可以看到只有一个counter而已。

注册store
store/configureStore.js

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import reducer from '../reducers'//applyMiddleware来自redux可以包装 store 的 dispatch
//thunk作用是使action创建函数可以返回一个function代替一个action对象
const createStoreWithMiddleware = applyMiddleware(thunk
)(createStore)export default function configureStore(initialState) {const store = createStoreWithMiddleware(reducer, initialState)//热替换选项if (module.hot) {// Enable Webpack hot module replacement for reducersmodule.hot.accept('../reducers', () => {const nextReducer = require('../reducers')store.replaceReducer(nextReducer)})}return store
}

index.js

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import App from './containers/App'
import configureStore from './store/configureStore'const store = configureStore()render(<Provider store={store}><App /></Provider>,document.getElementById('root')
)

上述代码,我们干了几件事:

用中间件使action创建函数可以返回一个function代替一个action对象
如果在热替换状态(Webpack hot module replacement)下,允许替换reducer
导出store
将store放进provider
将provider放在组件顶层,并渲染
applyMiddleware、thunk
applyMiddleware来自redux可以包装 store 的 dispatch()

thunk作用使action创建函数可以返回一个function代替一个action对象

服务
server.js

var webpack = require('webpack')
var webpackDevMiddleware = require('webpack-dev-middleware')
var webpackHotMiddleware = require('webpack-hot-middleware')
var config = require('./webpack.config')var app = new (require('express'))()
var port = 3000var compiler = webpack(config)
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }))
app.use(webpackHotMiddleware(compiler))app.get("/", function(req, res) {res.sendFile(__dirname + '/index.html')
})app.listen(port, function(error) {if (error) {console.error(error)} else {console.info("==> ��  Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port)}
})

webpack.config.js

var path = require('path')
var webpack = require('webpack')module.exports = {devtool: 'cheap-module-eval-source-map',entry: ['webpack-hot-middleware/client','./index'],output: {path: path.join(__dirname, 'dist'),filename: 'bundle.js',publicPath: '/static/'},plugins: [new webpack.optimize.OccurenceOrderPlugin(),new webpack.HotModuleReplacementPlugin(),new webpack.NoErrorsPlugin()],module: {loaders: [{test: /\.js$/,loaders: [ 'babel' ],exclude: /node_modules/,include: __dirname}]}
}

npm start 后执行node server ,触发webpack。webpack插件功能如下:

OccurenceOrderPlugin的作用是给经常使用的模块分配最小长度的id。
HotModuleReplacementPlugin是热替换,热替换和dev-server的hot有什么区别?不用刷新页面,可用于生产环境。
NoErrorsPlugin用于保证编译后的代码永远是对的,因为不对的话会自动停掉。
webpackHotMiddleware

server.js中webpackHotMiddleware的用法是参考官网的,没有为什么,express中间件就是在请求后执行某些操作。

教程源代码及目录
https://github.com/lewis617/react-redux-tutorial

这篇关于react+redux教程(一)connect、applyMiddleware、thunk、webpackHotMiddleware的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1016012

相关文章

使用Docker构建Python Flask程序的详细教程

《使用Docker构建PythonFlask程序的详细教程》在当今的软件开发领域,容器化技术正变得越来越流行,而Docker无疑是其中的佼佼者,本文我们就来聊聊如何使用Docker构建一个简单的Py... 目录引言一、准备工作二、创建 Flask 应用程序三、创建 dockerfile四、构建 Docker

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

前端如何通过nginx访问本地端口

《前端如何通过nginx访问本地端口》:本文主要介绍前端如何通过nginx访问本地端口的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、nginx安装1、下载(1)下载地址(2)系统选择(3)版本选择2、安装部署(1)解压(2)配置文件修改(3)启动(4)

Java Web实现类似Excel表格锁定功能实战教程

《JavaWeb实现类似Excel表格锁定功能实战教程》本文将详细介绍通过创建特定div元素并利用CSS布局和JavaScript事件监听来实现类似Excel的锁定行和列效果的方法,感兴趣的朋友跟随... 目录1. 模拟Excel表格锁定功能2. 创建3个div元素实现表格锁定2.1 div元素布局设计2.

HTML中meta标签的常见使用案例(示例详解)

《HTML中meta标签的常见使用案例(示例详解)》HTMLmeta标签用于提供文档元数据,涵盖字符编码、SEO优化、社交媒体集成、移动设备适配、浏览器控制及安全隐私设置,优化页面显示与搜索引擎索引... 目录html中meta标签的常见使用案例一、基础功能二、搜索引擎优化(seo)三、社交媒体集成四、移动

HTML input 标签示例详解

《HTMLinput标签示例详解》input标签主要用于接收用户的输入,随type属性值的不同,变换其具体功能,本文通过实例图文并茂的形式给大家介绍HTMLinput标签,感兴趣的朋友一... 目录通用属性输入框单行文本输入框 text密码输入框 password数字输入框 number电子邮件输入编程框

HTML img标签和超链接标签详细介绍

《HTMLimg标签和超链接标签详细介绍》:本文主要介绍了HTML中img标签的使用,包括src属性(指定图片路径)、相对/绝对路径区别、alt替代文本、title提示、宽高控制及边框设置等,详细内容请阅读本文,希望能对你有所帮助... 目录img 标签src 属性alt 属性title 属性width/h

SpringBoot连接Redis集群教程

《SpringBoot连接Redis集群教程》:本文主要介绍SpringBoot连接Redis集群教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 依赖2. 修改配置文件3. 创建RedisClusterConfig4. 测试总结1. 依赖 <de

CSS3打造的现代交互式登录界面详细实现过程

《CSS3打造的现代交互式登录界面详细实现过程》本文介绍CSS3和jQuery在登录界面设计中的应用,涵盖动画、选择器、自定义字体及盒模型技术,提升界面美观与交互性,同时优化性能和可访问性,感兴趣的朋... 目录1. css3用户登录界面设计概述1.1 用户界面设计的重要性1.2 CSS3的新特性与优势1.

HTML5 中的<button>标签用法和特征

《HTML5中的<button>标签用法和特征》在HTML5中,button标签用于定义一个可点击的按钮,它是创建交互式网页的重要元素之一,本文将深入解析HTML5中的button标签,详细介绍其属... 目录引言<button> 标签的基本用法<button> 标签的属性typevaluedisabled