React---Redux的使用
Redux 的适用场景:多交互、多数据源。
Redux对于JavaScript应用而言是一个可预测状态的容器。换言之,它是一个应用数据流框架,而不是传统的像underscore.js或者AngularJs那样的库或者框架。
Redux最主要是用作应用状态的管理。简言之,Redux用一个单独的常量状态树(对象)保存这一整个应用的状态,这个对象不能直接被改变。当一些数据变化了,一个新的对象就会被创建(使用actions和reducers)。
redux 是一个范用的状态管理框架
主要是解决了组件间状态共享的问题
原理是集中式管理
不是所有的项目都需要使用redux
redux的流程
View调用store.dispatch发起Action->store接受Action(action传入reducer函数,reducer函数返回一个新的state)->通知store.subscribe订阅的重新渲染函数
redux和flux的区别
Redux和Flux很像。主要区别在于Flux有多个可以改变应用状态的store,它通过事件来触发这些变化。组件可以订阅这些事件来和当前状态同步。
Redux没有分发器dispatcher,但在Flux中dispatcher被用来传递数据到注册的回调事件。另一个不同是Flux中有很多扩展是可用的,这也带来了一些混乱与矛盾
在redux当中只能定义一个可以更新状态的store
flux可以定义多个仓库
redux把store和Dispatcher合并,结构更加简单清晰
新增state,对状态的管理更加明确
redux和vuex的区别
改进了Redux中的Action和Reducer函数,以mutations变化函数取代Reducer,无需switch,只需在对应的mutation函数里改变state值即可
由于Vue自动重新渲染的特性,无需订阅重新渲染函数,只要生成新的State即可
redux的优点
redux把流程规范了,统一渲染根节点虽然对代码管理上规范了一些,只要有需要显示数据的组件,当相关数据更新时都会自动进行更新。
减少手动编码量,提高编码效率。
redux的缺点
一个组件所需要的数据,当相关数据更新时,组件要重新render,可能会有效率影响,或者需要写复杂的shouldComponentUpdate进行判断。
redux
redux中有三个基本概念,Action,Reducer,Store。
store 仓库
维持应用的 state;
提供 getState() 方法获取 state;
提供 dispatch(action) 方法更新 state;
通过 subscribe(listener) 注册监听器。
action 中发送过来的对象 必须有一个type属性
reducer 他是一个纯函数 他会跟action发送过来的type类型做逻辑上的处理(使用switch方法进行判断)
Redux核心API-reducer
Reducer 函数最重要的特征是,它是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出。
约束:
1、不得改写参数
2、不能调用系统 I/O 的API
3、不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果
Reducer 函数里面不能改变 State,必须返回一个全新的对象,请参考下面的写法。
// State 是一个对象
function reducer(state, action) {
return Object.assign({}, state, { thingToChange });
// 或者
return { ...state, ...newState };
}
// State 是一个数组
function reducer(state, action) {
return [...state, newItem];
}
安装 npm install redux -D
一、Redux核心API
引入必要组件:
import { createStore} from 'redux';
生成store:
const store = createStore(reducer, state初始状态[可选]);
取得当前时刻的state:
const state = store.getState();
发出action
store.dispatch({
type: 'ADD_TODO',
text: 'Learn Redux'
});
设置监听函数:
store.subscribe(callback);
二.Reducer拆分
import {combineReducers} from 'redux';
Const reducer=combineReducers({
Xxx:xxx(函数-业务逻辑)
})
二.Middleware的由来
1、middleware的由来
在redux里,action仅仅是携带了数据的普通js对象。action creator返回的值是这个action类型的对象。然后通过store.dispatch()进行分发。
同步的情况下一切都很完美,但是reducer无法处理异步的情况。
例如:我希望点击一个按钮,2秒之后更新视图,显示消息“Hi”。
那么我们就需要在action和reducer中间架起一座桥梁来处理异步。这就是middleware
2、理解middleware机制
参考代码:
export default function thunkMiddleware({ dispatch, getState }) {
return next => action =>
typeof action === 'function' ?
action(dispatch, getState) :
next(action);
}
这段代码的意思是,中间件这个桥梁接受到的参数action,如果不是function则和过去一样直接执行next方法(下一步处理)。相当于中间件没有做任何事。
如果action是function,则先执行action,action的处理结束之后,再在action的内部调用dispatch。
三. Redux异步流
使用middleware简化异步请求
使用middleware处理复杂异步流
redux-thunk:
store.dispatch参数可以是一个function
使用方法:
1.引入:
import thunk from 'redux-thunk';
2.加入中间件
const store = createStore(fetchReducer, applyMiddleware(thunk));
Actions.js
var Action={
addItem(text){
return{
type:'ADD_TODO',
text:text
}
},
rmItem(text){
return{
type:'RM_TODO',
text:text
}
},
loginItem(text){
return{
type:"ADD_Login",
text:text
}
},
addCount(text){
return{
type:"ADD_Count",
text:text
}
}
}
export default Action;
Demo.js
Demo.js
import React from "react";
import Action from "./Action" //把数据传给Action处理一下
import Store from "./Store";
class Demo extends React.Component{
constructor(props){
super(props)
//把start中所有的数据都给取出来
this.state={
// arr:Store.getState() //合并的写法
arr:Store.getState().list,
user:Store.getState().users,
count:Store.getState().count
}
this.changes = this.changes.bind(this)
}
changes(){
//修改setState的时候
this.setState({arr:Store.getState().list,user:Store.getState().users,count:Store.getState().count})
}
componentDidMount(){
Store.subscribe(this.changes) //监听
}
add(){
Store.dispatch(Action.addItem(this.refs.ipt.value)) //数据给store的dispatch方法接收
this.refs.ipt.value=""
}
del(i){
Store.dispatch(Action.rmItem(i))
}
login(){
Store.dispatch(Action.loginItem(this.refs.username.value))
this.refs.username.value=""
}
tap(){
Store.dispatch((dispatch)=>{ //用来操作异步操作
setTimeout(() => {
dispatch(Action.addCount(1))
}, 2000);
})
}
render(){
var _this = this;
return(
<div>
<h1>Redux----{this.state.user}</h1>
<input type="text" ref="ipt"/>
<div>
用户名:<input type="text" ref="username"/>
<button onClick={this.login.bind(this)}>登陆</button>
</div>
<button onClick={this.add.bind(this)}>增加</button>
<hr/>
<p>{this.state.count}</p>
<button onClick={this.tap.bind(this)}>累加</button>
{
this.state.arr.map(function(item,i){
return(
<div key={i}>{item}----<button onClick={_this.del.bind(_this,i)}>删除</button></div>
)
})
}
</div>
)
}
}
export default Demo;
Reducer.js
import {combineReducers} from "redux"; //拆分写法
import TodoList from "./TodoList"
import TodoLogin from "./TodoLogin"
import TodoCount from "./TodoCount"
// var Reducer = function (state=[],action) { //写在一起的
// switch (action.type) { //判断actoin的type类型
// case 'ADD_TODO': //添加
// let newstate = [...state]; //拷贝原本的state
// newstate.push(action.text)
// return newstate; //判断是否符合,符合返回newstate
// case 'RM_TODO': //删除
// let newstateS = [...state]; //拷贝原本的state
// newstateS.splice(action.text,1)
// return newstateS; //判断是否符合,符合返回newstate
// default:
// return state;
// }
// }
//当前数据为空,当有新数据传来的时候往数组里面push
var Reducer = combineReducers({
list:TodoList,
users:TodoLogin,
count:TodoCount
})
export default Reducer;
Store.js
import {createStore,applyMiddleware} from 'redux'; //创建store
import thunk from 'redux-thunk'; //处理异步
import Reducer from "./Reducer";
var Store=createStore(Reducer,applyMiddleware(thunk)) //允许异步请求,必须安装依赖redux-thunk
export default Store
TodoList.js
var TodoList = function(state=[],action) { //写在一起的
switch (action.type) { //判断actoin的type类型
case 'ADD_TODO': //添加
let newstate = [...state]; //拷贝原本的state
newstate.push(action.text)
return newstate; //判断是否符合,符合返回newstate
case 'RM_TODO': //删除
let newstateS = [...state]; //拷贝原本的state
newstateS.splice(action.text,1)
return newstateS; //判断是否符合,符合返回newstate
default:
return state;
}
}
export default TodoList;
TodoLogin.js
var TodoLogin=(state='',action)=>{
switch (action.type){
case 'ADD_Login':
let newstate=state
newstate=action.text;
return newstate;
default:
return state;
}
}
export default TodoLogin;
TodoCount.js
var TodoCount=(state=1,action)=>{
switch (action.type){
case 'ADD_Count':
let newstate=state;
newstate+=action.text;
return newstate
default:
return state
}
}
export default TodoCount;