安装

npm i -S redux react-redux redux-devtools

概念

在redux中分为3个对象:Action、Reducer、Store

Action

  1. 对行为(如用户行为)的抽象
  2. Action 就是一个普通 JavaScript 对象。如:{ type: 'ADD_TODO', text: 'Go to swimming pool' }(其中type字段是约定也是必须的)
  3. 作为Reducer的参数

Reducer

  1. 一个普通的函数,用来修改store的状态。
  2. 函数签名:(currentState,action)=>newState
    1. 在 default 情况下返回currentState
    2. Object.assign({},state, { visibilityFilter: action.filter })(第一个参数不能为state) 等价于ES7的 { ...state, ...newState }
  3. redux 的 combineReducers 方法可合并reducer

Store

  1. 代表数据模型,内部维护了一个state变量
  2. 两个核心方法,分别是getState、dispatch。前者用来获取store的状态(state),后者用来修改store的状态
  3. createStore(reducer) 可创建Store

redux示例:

import { createStore } from 'redux'

// reducer
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
default:
return state
}
} // state
let store = createStore(counter); // 会调用 // 监听
store.subscribe(() =>
console.log(store.getState())
); // 调用reducer
store.dispatch({ type: 'INCREMENT' });

react-redux

react的需求:

  1. 数据总是单向从顶层向下分发的
  2. 组件之间的沟通通过提升state:子组件改变父组件state的办法只能是通过onClick触发父组件声明好的回调
  3. state越来越复杂:单页应用的发展导致。包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。

react-redux 将react组件分为2种:展示组件 和 容器组件

展示组件

描述如何展示:负责UI样式的展示

  1. 数据来源:props
  2. 数据修改:通过props的回调函数
  3. 不直接使用redux

容器组件

描述如何运行:负责数据获取 和 状态更新

  1. 数据来源:redux state
  2. 数据修改:redux 派发action
  3. 直接使用redux

react-redux 只有2个API:Provider 和 connect

Provider

<Provider store>

  1. 在原应用组件上包裹一层,使原来整个应用成为Provider的子组件
  2. 接收Redux的store作为props,内部通过context对象传递给子孙组件上的connect

connect

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])(Component)

作用:连接React组件与 Redux store

mapStateToProps(state, ownProps) : stateProps

  1. 将 store 中的数据作为 props 绑定到组件上。
  2. 当 state 变化,或者 ownProps 变化的时候,mapStateToProps 都会被调用,计算出一个新的 stateProps

mapDispatchToProps(dispatch, ownProps): dispatchProps:将 dispatch(action) 作为 props 绑定到组件上

mergeProps:指定 stateProps 以及 dispatchProps 合并到 ownProps 的方式。(默认使用Object.assign)

connect是个高阶组件(HOC)大致源码:

export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
return function wrapWithConnect(WrappedComponent) {
class Connect extends Component {
constructor(props, context) {
this.store = props.store || context.store
this.stateProps = computeStateProps(this.store, props)
this.dispatchProps = computeDispatchProps(this.store, props)
this.state = { storeState: null }
// 合并stateProps、dispatchProps、parentProps
this.updateState()
}
shouldComponentUpdate(nextProps, nextState) {
// 进行判断,当数据发生改变时,Component重新渲染
if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
this.updateState(nextProps)
return true
}
}
componentDidMount() {
this.store.subscribe( () => this.setState({ storeState: this.store.getState() }) )
}
render() {
return (
<WrappedComponent {...this.nextState} />
)
}
}
return Connect;
}
}

react-redux示例:

Counter.js

import React, { Component } from 'react';
import { createStore, bindActionCreators } from 'redux';
import { Provider, connect } from 'react-redux'; function clickReduce(state = { todo: 1 }, action) {
switch (action.type) {
case 'click':
return Object.assign({}, state, { todo: state.todo + 1 });
default:
return state;
}
} let store = createStore(clickReduce); class Counter extends Component {
render() {
return (
<div>
<div>{this.props.todo}</div>
<button onClick={this.props.clickTodo}>Click</button>
</div>
)
}
} // 方式1:
export default connect(state => ({ todo: state.todo }),
dispatch => ({ clickTodo: () => dispatch({ type: 'click' }) }))(Counter) // 方式2:
export default connect(state => ({ todo: state.todo }),
dispatch => bindActionCreators({ clickTodo: () => ({ type: 'click' }) }, dispatch))(Counter);

index.js

import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { render } from 'react-dom';
import Clock from './Clock' render((
<Provider store={store}>
<Counter />
</Provider>), root);

在redux中,我们只能dispatch简单的action对象。

对应的在react-redux中,我们只能定义同步的reducer方法。

下节将介绍在react-redux如何定义异步方法。让其更加适用于生产环境。

最新文章

  1. C# - 多线程 之 Process与Thread与ThreadPool
  2. MySQL修改root账号密码
  3. Shell 编程基础之注意技巧
  4. java.lang.UnsupportedClassVersionError: xxx/xxxClass : Unsupported major.minor version 51.0
  5. response实现验证码图片
  6. java中String.valueOf()和toString()方法的区别
  7. 局部内部类访问方法中的局部变量为什么加final
  8. PHPCMS数据筛选功能实现
  9. 使用JPA TOOLS从数据库生成Entity文件
  10. 反对抄袭 正解spring的@Autowired 不要相信网上的错误版本
  11. paip.QQ音乐导出歌单总结
  12. TCP/IP协议栈 -----链路层
  13. 查找 GPU 计算能力
  14. Python 使用 virtualenvwrapper 安装虚拟环境
  15. 机器学习---文本特征提取之词袋模型(Machine Learning Text Feature Extraction Bag of Words)
  16. [PyImageSearch] Ubuntu16.04 使用OpenCV和python识别信用卡 OCR
  17. js-redux学习笔记
  18. Django之MVC与MTV
  19. 默认情况下eth0网卡配置文件路径及客户端DNS的路径
  20. RxJava 中文文档

热门文章

  1. SharePoint JS感悟-js脚本
  2. LeetCode(25)-symmetric tree
  3. ELF 动态链接 - so 的 .dynamic 段
  4. java多继承
  5. getContext在谷歌浏览器中,使用时要先加载canvas对象,否则会提示&#39;getContext is null&#39;
  6. Go语言开发区块链只需180行代码
  7. 关于php中openssl_public_encrypt无填充的一个注意事项
  8. SOFA 源码分析 — 自定义线程池原理
  9. SOFA 源码分析 —— 服务发布过程
  10. java 用ant打包成jar文件