React 只是 DOM 的一个抽象层(ui),并不是 Web 应用的完整解决方案。有两个方面,它没涉及。
* 代码结构
* 组件之间的通信
为了解决这个问题,2014年 Facebook 提出了 Flux 架构的概念,引发了很多的实现。2015年,Redux 出现,将 Flux 与函数式编程结合一起,很短时间内就成为了最热门的前端架构
简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。
* 用户的使用方式非常简单
* 用户之间没有协作
* 不需要与服务器大量交互,也没有使用 WebSocket
* 视图层(View)只从单一来源获取数据
下面情况才是 Redux 的适用场景:多交互、多数据源。
* 用户的使用方式复杂
* 不同身份的用户有不同的使用方式(比如普通用户和管理员)
* 多个用户之间可以协作
* 与服务器大量交互,或者使用了WebSocket
* View要从多个来源获取数据
从组件角度看,如果你的应用有以下场景,可以考虑使用 Redux。
* 某个组件的状态,需要共享
* 某个状态需要在任何地方都可以拿到
* 一个组件需要改变全局状态
* 一个组件需要改变另一个组件的状态
Redux 的设计思想很简单,就两句话。
1. Web 应用是一个状态机,视图与状态是一一对应的。
2. 所有的状态,保存在一个对象里面(唯一数据源)
redux的小案例:理解这个案例就感觉明白了好多;
cnpm i redux -S
```
import {createStore} from 'redux'
import reducer from './reducer'
const Store = createStore(reducer);
export default Store
```
reduers:是一个纯函数Reducer; 函数负责生成 State。由于整个应用只有一个 State 对象,包含所有数据,
import {ADD_NUMBER, REDUCE_NUMBER} from './TYPES'
//创建初始状态
let _state = {
num:1
}
const reducer = (state = _state,action)=>{
if(action.type == '@@redux/INIT'){
console.log('1. Store通过reducer创建了初始状态')
}
let _state = Object.assign({},state)
// alert(action.type)//默认执行的,redux自有的
//必须有返回值
switch(action.type){
case ADD_NUMBER:
console.log('6.reducer接收到action并根据信息判断知乎返回新的state')
_state.num ++;
return _state;break;
case REDUCE_NUMBER:
_state.num --;
return _state;break;
default:
return state;break;
}
return state
}
export default reducer
cnpm i redux -S counter:计数器 ``` import React from 'react'; import PropTypes from 'prop-types'; import Store from '../redux/store' import Button from './Button' //调用actions中的方法 import actions from '../redux/actions' class Counter extends React.Component{ constructor(props){ super(props) this.state = { num:Store.getState().num } console.log('2.view通过Store.getState()获取到了store挂在在自己的状态') this.handleAddNumber = this.handleAddNumber.bind(this) // this.handleReduceNumber = this.handleReduceNumber.bind(this) } handleAddNumber(){ console.log('3.用户产生了操作调用了action方法') actions.addNumber() } // handleReduceNumber(){ // actions.reduceNumber() // } componentWillMount(){ Store.subscribe(function(){ console.log('7.store的reducer更改为新的state的时候,store.subscribe方法里的回调函数会执行,此时就可以通知view去重新获取state') this.setState({num:Store.getState().num}) }.bind(this)) } render(){ let {num} = this.state return( <div> <Button handler = {actions.reduceNumber}>-</Button> {num} <Button handler = {this.handleAddNumber}>+</Button> </div> ) } } Counter.defaultProps = { } Counter.propTypes = { } export default Counter
action:是一个穿对象,包含一些方法;
```
import {ADD_NUMBER,REDUCE_NUMBER} from './TYPES'
//需要调用store的方法
import Store from './store'
//纯对象,包含一些方法
const actions = {
addNumber(){
console.log('4.actions的方法被调用,创建了带有标示信息的action')
let action = {
type:ADD_NUMBER
}
console.log('5.actions同故调用actions.dispatch方法传递给reducer')
Store.dispatch(action)
},
reduceNumber(){
let action = {
type:REDUCE_NUMBER
}
Store.dispatch(action)
}
//发送给store
}
export default actions
TYPES:
```
const ADD_NUMBER = 'ADD_NUMBER'
const REDUCE_NUMBER = 'REDUCE_NUMBER'
export {ADD_NUMBER,REDUCE_NUMBER}
```
注意:flux,redux都不是必须和react搭配使用的,因为flux和redux使完整的架构,在学习react的时候,只是将
Reducer 函数最重要的特征是,它是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出。
纯函数是函数式编程的概念,必须遵守以下一些约束。
* 不得改写参数
* 不能调用系统 I/O 的API
* 不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果;可以放在action里进行操作
划分reducer
因为一个应用中只能有一个大的state,这样的话reducer中的代码将会特别特别的多,那么可以使用combineReducers方法将已经分开的renducer合并到一起
```
// State 是一个数组
function reducer(state, action) {
return [...state, newItem];
}
```
最好把 State 对象设成只读。你没法改变它,要得到新的 State,唯一办法就是生成一个新对象。这样的好处是,任何时候,与某个 View 对应的 State 总是一个不变的对象。
注意:
1. 分离reducer的时候,每一个reducer维护的状态都应该不同
2. 通过store.getState获取到的数据也是会安装reducers去划分的
无状态组件里含有react