前几天,我在博文【前端】一步一步使用 webpack+react+sCSS 脚手架重构项目 中搭建了一个 react 开发环境。然而在实际的开发过程中,或者是在对源码的理解中,感受到 react 中用的最多的,就是 redux 了,于是打开文档学习了一番。在这里做一些记录。
redux 是什么?它是用来管理状态的。在 react 开发中,我们经常会遇到一种情况,组件与父组件之间的通信,组件与组件之间的通信,
其中组件与父组件的通信通过 props 来完成。
- /***********parent****************/
- <Number
- value={this.state.number}
- />
- /***********number****************/
- <div >{this.props.value}</div>
number 内部使用 props 获取父组件自己的 state,通过 setState 更改父组件的 state.number 可以实现 number 组件的实时更新。
那么组件与组件之间的通信呢?例如我们有 a,b 两个组件,现在 a 要给 b 转发一个激活状态 active,一般思路是,在同一个父组件下,使用 props 传递回调函数的方式。
- /*********组件 a**********/
- class A {.....changeActive() {
- this.props.changebActive();
- }
- render() {
- return < button onClick = {
- this.changeActive
- } > </button>
- }
- }
- / * ********组件b * *********/
- class B{
- render(){
- return <div>状态:{this.props.active}</div >
- }
- }
- /*********组件 parent**********/
- class parent {......changebActive() {
- this.setState({
- active: "开启"
- })
- }
- render() {
- return < div > <A changebActive = {
- this.changebActive.bind(this)
- }
- />
- <B
- active={this.state.active}
- / > </div>
- }
- }/
通过 A 点击调用到 parent 的 changebActive 方法,设置 state 更新 b,这种方式非常容易使项目变得不可预测,并且 state 管理复杂,没错,redux 很大程度就是用来解决这个问题的,它在 react 中的思想是:
将组件状态统一放到同一个超级父组件,再由这个超级父组件用更专业的方法分发 props 给所有的子组件,无论嵌套多少层。由超级父组件统一管理应用中所有的 state。
--- 这就是 redux。无论 api 名词如何晦涩难懂,它的核心思想是在开发中浮现的。
一、所有的状态,保存在一个对象里面。
所有的状态都保存在一个对象里面,redux 基本三大原则之一,单一数据源,一个应用所有的状态被保存在一个对象里,这个对象通过 store 管理,想象一下,整个页面的状态被存储在一个对象里面,其实类似一个配置文件,你可以从服务器读取,可以从任何地方改变。view 则是同步的,这看起来更精炼不是么。
二、store
Store 就是保存状态数据对象的地方,你可以把它看成一个容器。整个应用只能有一个 Store。
Redux 提供
这个函数,用来生成 Store。createStore 传入了一个函数这个函数将接收到两个参数,一个 state,一个 action,action 就是由子组件发出的更改请求,state 就是那个单一的 state 对象。
- createStore
- import { createStore } from 'redux';
- const store = createStore(fn);
三、action
发起状态改变的起点是 action,由子组件发出 action,子组件通过 props 调用回调函数,通知父组件发出 action。
触发:
- store.dispatch(action);
四、store.dispatch
这个方法就是发出 action 的方法,一般传入 action,调用这个方法之后,会触发在 createStore 中传入的函数。
五、store.getState
它用来获取当前的 state 对象
六、reducer
这个就是 createStore 中传入的函数的名词解释,这个函数的执行必须返回一个新的 state:
- export default (state={number:0},action)=>{//每次调用都会传入state和当前通知的action
- switch(action.type){
- case "NUMBER_ADD": //发过来的action如果是NUMBER_ADD 就返回number++
- state.number++;
- break;
- case "NUMBER_LESS":
- state.number--;
- break;
- }
- return Object.assign({},state); //必须返回一个新的state ,可以使用assign合并
- }
注意这里用了 es6,给 state 添加了一个默认值,{number:0}。
六、store.subscribe()
Store 允许使用
方法设置监听函数,一旦 State 发生变化,就自动执行这个函数。
- store.subscribe
- import { createStore } from 'redux';
- const store = createStore(reducer);
- store.subscribe(render);
比如上面我在生成 store 传入 reducer 函数之后,使用 store.subscribe() 设置监听函数为 render,则每次 state 改变了,就会执行 render 函数,刷新视图。
实践一个 number 输入框的加减组件,你就能大概知道 redux 究竟是怎么工作的。
一、准备
首先你需要搭建一个 react 的开发环境,需要一个 index.html 输出目录等。详见我的另一篇博文:【前端】一步一步使用 webpack+react+scss 脚手架重构项目 。
然后你需要一定的 react 开发实践,React 有 props 和 state 两个属性: props 意味着父组件分发下来的属性,state 意味着组件内部可以自行管理的状态,并且整个 React 没有数据向上回溯的能力,也就是说数据只能单向向下分发,或者自行内部消化。
理解这个是理解 React 和 Redux 的前提。
你需要 npm 安装 redux:
num install redux react-redux --save-dev
二、代码
1.number.js
- import React,{Component} from "react";
- const propTypes = {
- add:React.PropTypes.func.isRequired,
- less:React.PropTypes.func.isRequired,
- value:React.PropTypes.object.isRequired
- }
- class Number extends Component{
- add(){
- this.props.add({type:"NUMBER_ADD"}) //调用app.js中传过来的箭头函数,传入了type为NUMBER_ADD的action
- }
- less(){
- this.props.less({type:"NUMBER_LESS"})
- }
- render(){
- return <div>
- <input type="text" value={this.props.value.number}/>
- <button onClick={this.add.bind(this)}>
- +
- </button>
- <button onClick={this.less.bind(this)}>
- -
- </button>
- </div>
- }
- }
- Number.propTypes = propTypes;
- export {Number};
注意那两个 click 回调,发出了 action,以及那个 this.props.value.number 的引用,props 传入了 state,获取了 state.number
2.app.js
- import React from "react";
- import ReactDOM from "react-dom";
- import {createStore} from "redux"; //导入createStore
- import {Number} from "./number.js";
- import reducers from "./reducers.js";
- const store = createStore(reducers); //生成store
- const content = document.querySelector(".content");
- const render = ()=> ReactDOM.render(
- <div>
- <Number
- value={store.getState()}
- add={(action)=>store.dispatch(action)} //传入一个函数,传入发送过来的action,由reducers处理之后返回state,
- less={(action)=>store.dispatch(action)}
- />
- </div>,
- content
- );
- render();
- store.subscribe(render); //在reducers处理之后,返回了state,然后触发了render,更新视图
3.reducers.js
- export default (state={number:0},action)=>{//每次调用都会传入state和当前通知的action
- switch(action.type){
- case "NUMBER_ADD": //发过来的action如果是NUMBER_ADD 就返回number++
- state.number++;
- break;
- case "NUMBER_LESS":
- state.number--;
- break;
- }
- return Object.assign({},state); //必须返回一个新的state ,可以使用assign合并
- }
这就是 createStore 传入的函数,当发出 action,store 会自动调用它传入 state,action 返回了一个新的 state.
Redux 的基本用法就介绍到这里,下一篇介绍它的高级用法:中间件和异步操作。为什么是下一篇?因为我也还没学。
阮一峰的教程
number——demo 的 github
知乎上大神对 redux 的易懂解读
来源: http://www.cnblogs.com/ztfjs/p/redux.html