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

例子

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

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

组件

components/Counter.js

  1. import React, { Component, PropTypes } from 'react'
  2.  
  3. class Counter extends Component {
  4. render() {
  5. //从组件的props属性中导入四个方法和一个变量
  6. const { increment, incrementIfOdd, incrementAsync, decrement, counter } = this.props;
  7. //渲染组件,包括一个数字,四个按钮
  8. return (
  9. <p>
  10. Clicked: {counter} times
  11. {' '}
  12. <button onClick={increment}>+</button>
  13. {' '}
  14. <button onClick={decrement}>-</button>
  15. {' '}
  16. <button onClick={incrementIfOdd}>Increment if odd</button>
  17. {' '}
  18. <button onClick={() => incrementAsync()}>Increment async</button>
  19. </p>
  20. )
  21. }
  22. }
  23. //限制组件的props安全
  24. Counter.propTypes = {
  25. //increment必须为fucntion,且必须存在
  26. increment: PropTypes.func.isRequired,
  27. incrementIfOdd: PropTypes.func.isRequired,
  28. incrementAsync: PropTypes.func.isRequired,
  29. decrement: PropTypes.func.isRequired,
  30. //counter必须为数字,且必须存在
  31. counter: PropTypes.number.isRequired
  32. };
  33.  
  34. export default Counter

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

  1. 从props中导入变量和方法
  2. 渲染组件

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

容器

containers/App.js

  1. import { bindActionCreators } from 'redux'
  2. import { connect } from 'react-redux'
  3. import Counter from '../components/Counter'
  4. import * as CounterActions from '../actions/counter'
  5.  
  6. //将state.counter绑定到props的counter
  7. function mapStateToProps(state) {
  8. return {
  9. counter: state.counter
  10. }
  11. }
  12. //将action的所有方法绑定到props上
  13. function mapDispatchToProps(dispatch) {
  14. return bindActionCreators(CounterActions, dispatch)
  15. }
  16.  
  17. //通过react-redux提供的connect方法将我们需要的state中的数据和actions中的方法绑定到props上
  18. export default connect(mapStateToProps, mapDispatchToProps)(Counter)

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

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

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

  1. 把state的counter值绑定到props上
  2. 把四个action创建函数绑定到props上

connect

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

  1. 第一个参数,必须是function,作用是绑定state的指定值到props上面。这里绑定的是counter
  2. 第二个参数,可以是function,也可以是对象,作用是绑定action创建函数到props上。
  3. 返回值,是绑定后的组件

这里还有很多种其他写法,我喜欢在第二个参数绑定一个对象,即

  1. import { bindActionCreators } from 'redux'
  2. import { connect } from 'react-redux'
  3. import Counter from '../components/Counter'
  4. import * as CounterActions from '../actions/counter'
  5.  
  6. //将state.counter绑定到props的counter
  7. function mapStateToProps(state) {
  8. return {
  9. counter: state.counter
  10. }
  11. }
  12.  
  13. //通过react-redux提供的connect方法将我们需要的state中的数据和actions中的方法绑定到props上
  14. export default connect(mapStateToProps, CounterActions)(Counter)

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

  1. import { bindActionCreators } from 'redux'
  2. import { connect } from 'react-redux'
  3. import Counter from '../components/Counter'
  4. import * as CounterActions from '../actions/counter'
  5.  
  6. //将state.counter绑定到props的counter
  7. function mapStateToProps(state) {
  8. return {
  9. counter: state.counter
  10. }
  11. }
  12.  
  13. //通过react-redux提供的connect方法将我们需要的state中的数据绑定到props上
  14. export default connect(mapStateToProps)(Counter)

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

action和reducer两个好基友负责更新state

actions/counter.js

  1. export const INCREMENT_COUNTER = 'INCREMENT_COUNTER'
  2. export const DECREMENT_COUNTER = 'DECREMENT_COUNTER'
  3. //导出加一的方法
  4. export function increment() {
  5. return {
  6. type: INCREMENT_COUNTER
  7. }
  8. }
  9. //导出减一的方法
  10. export function decrement() {
  11. return {
  12. type: DECREMENT_COUNTER
  13. }
  14. }
  15. //导出奇数加一的方法,该方法返回一个方法,包含dispatch和getState两个参数,dispatch用于执行action的方法,getState返回state
  16. export function incrementIfOdd() {
  17. return (dispatch, getState) => {
  18. //获取state对象中的counter属性值
  19. const { counter } = getState()
  20.  
  21. //偶数则返回
  22. if (counter % 2 === 0) {
  23. return
  24. }
  25. //没有返回就执行加一
  26. dispatch(increment())
  27. }
  28. }
  29. //导出一个方法,包含一个默认参数delay,返回一个方法,一秒后加一
  30. export function incrementAsync(delay = 1000) {
  31. return dispatch => {
  32. setTimeout(() => {
  33. dispatch(increment())
  34. }, delay)
  35. }
  36. }
  37.  
  38. //这些方法都导出,在其他文件导入时候,使用import * as actions 就可以生成一个actions对象包含所有的export

reducers/counter.js

  1. import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../actions/counter'
  2.  
  3. //reducer其实也是个方法而已,参数是state和action,返回值是新的state
  4. export default function counter(state = 0, action) {
  5. switch (action.type) {
  6. case INCREMENT_COUNTER:
  7. return state + 1
  8. case DECREMENT_COUNTER:
  9. return state - 1
  10. default:
  11. return state
  12. }
  13. }

reducers/index.js

  1. import { combineReducers } from 'redux'
  2. import counter from './counter'
  3.  
  4. //使用redux的combineReducers方法将所有reducer打包起来
  5. const rootReducer = combineReducers({
  6. counter
  7. })
  8.  
  9. export default rootReducer

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

  1. 写了四个action创建函数
  2. 写了reducer用于更新state
  3. 将所有reducer(这里只有一个)打包成一个reducer

看到这里,有很多初次接触redux的同学可能已经晕了,怎么那么多概念?为了形象直观,我们在开发工具(react dev tools)上看看这些state,props什么的:

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

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

注册store

store/configureStore.js

  1. import { createStore, applyMiddleware } from 'redux'
  2. import thunk from 'redux-thunk'
  3. import reducer from '../reducers'
  4.  
  5. //applyMiddleware来自redux可以包装 store 的 dispatch
  6. //thunk作用是使action创建函数可以返回一个function代替一个action对象
  7. const createStoreWithMiddleware = applyMiddleware(
  8. thunk
  9. )(createStore)
  10.  
  11. export default function configureStore(initialState) {
  12. const store = createStoreWithMiddleware(reducer, initialState)
  13.  
  14. //热替换选项
  15. if (module.hot) {
  16. // Enable Webpack hot module replacement for reducers
  17. module.hot.accept('../reducers', () => {
  18. const nextReducer = require('../reducers')
  19. store.replaceReducer(nextReducer)
  20. })
  21. }
  22.  
  23. return store
  24. }

index.js

  1. import React from 'react'
  2. import { render } from 'react-dom'
  3. import { Provider } from 'react-redux'
  4. import App from './containers/App'
  5. import configureStore from './store/configureStore'
  6.  
  7. const store = configureStore()
  8.  
  9. render(
  10. <Provider store={store}>
  11. <App />
  12. </Provider>,
  13. document.getElementById('root')
  14. )

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

  1. 用中间件使action创建函数可以返回一个function代替一个action对象
  2. 如果在热替换状态(Webpack hot module replacement)下,允许替换reducer
  3. 导出store
  4. 将store放进provider
  5. 将provider放在组件顶层,并渲染

applyMiddleware、thunk

applyMiddleware来自redux可以包装 store 的 dispatch()

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

服务

server.js

  1. var webpack = require('webpack')
  2. var webpackDevMiddleware = require('webpack-dev-middleware')
  3. var webpackHotMiddleware = require('webpack-hot-middleware')
  4. var config = require('./webpack.config')
  5.  
  6. var app = new (require('express'))()
  7. var port = 3000
  8.  
  9. var compiler = webpack(config)
  10. app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }))
  11. app.use(webpackHotMiddleware(compiler))
  12.  
  13. app.get("/", function(req, res) {
  14. res.sendFile(__dirname + '/index.html')
  15. })
  16.  
  17. app.listen(port, function(error) {
  18. if (error) {
  19. console.error(error)
  20. } else {
  21. console.info("==>
  22. react+redux教程(一)connect、applyMiddleware、thunk、webpackHotMiddleware的更多相关文章

      1. react+redux教程(五)异步、单一state树结构、componentWillReceiveProps
      1. 今天,我们要讲解的是异步.单一state树结构.componentWillReceiveProps这三个知识点. 例子 这个例子是官方的例子,主要是从Reddit中请求新闻列表来显示,可以切换reac ...

      1. react+redux教程(四)undo、devtools、router
      1. 上节课,我们介绍了一些es6的新语法:react+redux教程(三)reduce().filter().map().some().every()....展开属性 今天我们通过解读redux-undo ...

      1. react+redux教程(二)redux的单一状态树完全替代了react的状态机?
      1. 上篇react+redux教程,我们讲解了官方计数器的代码实现,react+redux教程(一).我们发现我们没有用到react组件本身的state,而是通过props来导入数据和操作的. 我们知道r ...

      1. react+redux教程(八)连接数据库的redux程序
      1. 前面所有的教程都是解读官方的示例代码,是时候我们自己写个连接数据库的redux程序了! 例子 这个例子代码,是我自己写的程序,一个非常简单的todo,但是包含了redux插件的用法,中间件的用法,连接 ...

      1. react+redux教程(七)自定义redux中间件
      1. 今天,我们要讲解的是自定义redux中间件这个知识点.本节内容非常抽象,特别是中间件的定义原理,那多层的函数嵌套和串联,需要极强逻辑思维能力才能完全消化吸收.不过我会多罗嗦几句,所以不用担心. 例子 ...

      1. react+redux教程(六)redux服务端渲染流程
      1. 今天,我们要讲解的是react+redux服务端渲染.个人认为,react击败angular的真正“杀手锏”就是服务端渲染.我们为什么要实现服务端渲染,主要是为了SEO. 例子 例子仍然是官方的计数器 ...

      1. react+redux教程(三)reduce()、filter()、map()、some()、every()、...展开属性
      1. reduce().filter().map().some().every()....展开属性   这些概念属于es5.es6中的语法,跟react+redux并没有什么联系,我们直接在https:// ...

      1. react/redux组件库、模板、学习教程
      1. 开源的有蚂蚁金服的: 1.https://pro.ant.design/index-cn 2.https://pro.ant.design/docs/getting-started-cn 3.http ...

      1. 使用react+redux+react-redux+react-router+axios+scss技术栈从0到1开发一个applist应用
      1. 先看效果图 github地址 github仓库 在线访问 初始化项目 #创建项目 create-react-app applist #如果没有安装create-react-app的话,先安装 npm ...

    1.  
    2. 随机推荐

        1. JAVA_javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
        1. tomcat访问https请求返回: javax.net.ssl.SSLProtocolException: handshake alert:  unrecognized_name at sun.se ...

        1. Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)
        1. 互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...

        1. 【hihoCoder】1121:二分图一·二分图判定
        1.   题目   http://hihocoder.com/problemset/problem/1121 无向图上有N个点,两两之间可以有连线,共有M条连线. 如果对所有点进行涂色(白/黑),判定是否存 ...

        1. Maven 上传 jar包 到私服
        1. 登录Nexus后,点击右侧的“Repositories”,显示当前Nexus所管理的Repository, 默认情况下Nexus为我们创建了以下主要的Repository: 1.PublicRepos ...

        1. 后台PageVo中字段赋值与前台datagrid字段获取
        1. 后台PageVo中字段的geter与setter函数需根据pageVo的字段自动生成,前台字段与后台字段名保持一致. 数据返回到前台时,datagrid会根据字段名隐射到相应的getter与sette ...

        1. C# 5.0 异步编程
        1. 在C#5.0中,增加了一个强大的新功能--异步编程.( .NET FrameWork4.5  版本) 它以两个新型关键字出现: ·async ·await 1.Async方法有三种返回类型: asyn ...

        1. STL之关联容器
        1. 关联容器包含map.set.multimap.multiset. 关联容器的特点是明显的,相对于顺序容器,有如下特点: 1.其内部是采用非线性的二叉树结构,具体的说是红黑树的结构原理实现的. 2.se ...

        1. 微软开源.NET Core的执行引擎CoreCLR{转载}
        1. 继去年12月宣布.NET Core开源之后,微软拥抱开源的决心又向前迈了一步,Microsoft于昨日在 .NET Framework Blog上 宣布开源.NET Core 的执行引擎 CoreCL ...

        1. IIS 8:IIS 入门
        1. 深埋在您的 Microsoft 服务器 (2008年. 2008 R2 和 2012年的版本) 的范围内是最强大的 Web 服务器可用. 它只等待你来发挥其全部潜力. 您的目标是要从家里运行一个 Wo ...

        1. Windows+GCC下内存对齐的常见问题
        1. 结构/类对齐的声明方式 gcc和windows对于modifier/attribute的支持其实是差不多的.比如在gcc的例子中,内存对齐要写成: class X { //... } __attrib ...