React 将页面元素拆分红组件,经过组装展现数据。组件又有无状态和有状态之分,所谓状态,能够简单的认为是组件要展现的数据。React 有个特性或者说是限制单向数据流,组件的状态数据只能在组件内部修改,对于其余组件是只读的,想要修改只能经过组件提供的接口回调。html
随着组件数量的增多,组件间状态数据共享的复杂性也会随之增长,若是仅使用 React 组件内的 State 可能会致使程序的流程混乱,代码难以维护。react
原文连接:https://www.chuonye.com/archives/react-redux.html数据库
为何这么说呢,咱们来看一个图:redux
原始的 React,当最底层组件须要改变数据时,若是数据在父组件,回调方法层层传递便可;若是在兄弟组件,那就须要借助一个中间组件,固然了也有办法直接与兄弟组件通讯。能够想象,随着应用复杂程度的提升,组件间通讯使用的各类直接或间接回调,可能会致使代码乱成一团。antd
此时,Redux 就派上用场了,如上图所示,它把应用的全部状态-数据存储在一个地方,并称之为Store,组件间不直接通讯,而是把变化的数据推给 Store,须要根据状态变化从新渲染的组件经过订阅 Store 来实现。框架
Redux 在设计与实现时,遵循三大原则或者说规范限制。dom
整个应用程序的状态数据仅存储在一个 Store 中,数据就存储在一个大的对象树(object tree)中。ide
惟一的 Store 也是只读的,应用程序没法直接修改状态数据。Store 对象自己的 API 很是少,仅有四个方法:函数
getState()
: 获取当前状态数据dispatch(action)
: 推送触发变化subscribe(listener)
: 订阅数据变化replaceReducer(nextReducer)
显而易见,没有提供设置状态的方法。其中的 dispatch(action)
是惟一改变数据的方法,好比:工具
var action = { type: 'ADD_USER', user: {name: 'chuonye.com'} }; store.dispatch(action);
dispatch
方法会将 action
传递给 Redux,action 就是一个普通对象,包含触发的操做类型以及数据。
Redux 接收到 action
后,会使用一个纯函数来处理,这些函数被称为 Reducers:
var someReducer = function(state, action) { ... return state; }
Reducer 接收当前的 state 和 action 做为参数,它也不能直接修改原有的数据,而是经过返回一个新的 state 来修改。
总的来讲,Redux 是一个帮助应用统一管理状态数据的工具,它遵循严格的单向数据流(Store 只读)设计,使得应用的行为变得可预测且容易理解。
Redux 通常和 React 这类框架搭配使用,为了方便与 React 集成,Redux 官方提供了一个 react-redux 绑定库。react-redux 将组件划分为容器组件,UI组件和其余组件,其中:
从总体来看,在使用上,应用代码分层设计,结构以下:
咱们不妨结合着数据库,来理解下每一个层次的意思,从下往上:
这些设计怎么有点熟悉,跟 Java 是愈来愈像了。下面简单写个例子,看看到底怎么用。
接下来咱们按照使用原生 React,使用 Redux 和使用 React-Redux的顺序分别实现一个 Counter 计数器的功能。
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; class Counter extends Component { constructor(props) { super(props); this.state = { value: 0 }; // 状态数据 } render() { return ( <div> <p>state: {this.state.value}</p> <button onClick={() => this.handleIncrement()}>+1</button> <button onClick={() => this.handleDecrement()}>-1</button> </div> ); } // 处理方法 handleIncrement() { let curVal = this.state.value + 1; this.setState({value: curVal}); } handleDecrement() { let curVal = this.state.value - 1; this.setState({value: curVal}); } } // 渲染 ReactDOM.render(<Counter />, document.getElementById('root'))
import React from 'react'; import ReactDOM from 'react-dom'; import { createStore } from 'redux'; // 接收 action 并处理,签名:(state, action) => newState function reducer(state = {value: 0}, action) { let curVal = state.value; switch (action.type) { case 'INCREMENT': return {value: curVal+1}; case 'DECREMENT': return {value: curVal-1}; default: return state; } } // 建立 Redux store const store = createStore(reducer); const render = () => ReactDOM.render( <div> <p>state: {store.getState().value}</p> {/* dispatch 通知 store 改变数据 */} <button onClick={()=>{store.dispatch({type: 'INCREMENT'})}}>+1</button> <button onClick={()=>{store.dispatch({type: 'DECREMENT'})}}>-1</button> </div>, document.getElementById('root') ) render(); // 订阅 store,状态改变时更新 UI store.subscribe(render);
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import { createStore } from 'redux'; import { Provider, connect } from 'react-redux'; // 接收 action 并处理 function reducer(state = {value: 0}, action) { let curVal = state.value; switch (action.type) { case 'INCREMENT': return {value: curVal+1}; case 'DECREMENT': return {value: curVal-1}; default: return state; } } // 定义一个 UI 组件,用于展现数据 class CounterUI extends Component { render() { // 数据来源于 props const {value, handleIncrement, handleDecrement} = this.props; return ( <div> <p>state: {value}</p> <button onClick={handleIncrement}>+1</button> <button onClick={handleDecrement}>-1</button> </div> ); } } // 定义一个 容器组件,用于与 Redux store 交互 // 将 Redux state 按需注入到 UI 组件的 props function mapStateToProps(state) { return { value: state.value } } // 将 Redux actions 按需注入到 UI 组件的 props function mapDispatchToProps(dispatch) { return { handleIncrement: () => dispatch({type: 'INCREMENT'}), handleDecrement: () => dispatch({type: 'DECREMENT'}) } } // 使用 connect 方法基于 UI组件 生成一个 容器组件 const CounterContainer = connect(mapStateToProps, mapDispatchToProps)(CounterUI); const store = createStore(reducer); // 使用 Provider 做为根组件,使得全部子组件都能访问到 store ReactDOM.render( <Provider store={store}> <CounterContainer /> </Provider>, document.getElementById('root') )
Redux 和 React-Redux 专门设计了约束和约定,致使代码量不见得减小,甚至还可能增长了。简单的项目看不出有什么优点,但在构建必定规模的企业级项目时,这些约束和条条框框,会有利于项目的维护和管理。正如 Java,有些人认为过于啰嗦,但这正是它严谨的体现!
下一篇将会结合 antd UI框架模仿实现官方提供的购物车实例。