一、Redux核心
1.Redux核心概念及工作流程
Store:存储状态的容器,JavaScript对象
View:视图,html界面
Actions:对象,描述对状态进行怎样的操作
Reducers:函数,操作状态并返回新的状态
工作流程:视图如果想改变store中的状态,他无法直接更改,他必须要先去触发action,actions会被reducer接受到,他根据actions中的type去进行判断看一下他要进行什么样的操作,reducer会根据type属性值对State中的状态进行操作,处理完状态后会把新的状态值返回给store,最后store会把新的状态同步给视图。
2.计数器案例
// 3. 存储默认状态
var initialState = {
count: 0
}
// 2. 创建 reducer 函数,接受两个参数第一个为接受的默认状态,第二个参数接受action
function reducer (state = initialState, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1}
default:
return state;
}
}
// 1. 创建 store 对象,它可以传入两个参数,第一个为reducer改变state的方法,第二个为默认参数
var store = Redux.createStore(reducer);
// 4. 定义 action 描述要进行怎样的操作,type是一个自定义的字符串
var increment = { type: 'increment' };
var decrement = { type: 'decrement' };
// 5. 获取按钮 给按钮添加点击事件
document.getElementById('plus').onclick = function () {
// 6. 触发action 用dispatch方法触发action,dispatch方法存放在store实例里
store.dispatch(increment);
}
document.getElementById('minus').onclick = function () {
// 6. 触发action
store.dispatch(decrement);
}
// 7. 订阅 store
store.subscribe(() => {
// 获取store对象中存储的状态
// console.log(store.getState());
document.getElementById('count').innerHTML = store.getState().count;
})
3.Redux核心API
// 创建Store容器
const store = Redux.createStore(reducer)
// 创建用于处理状态的reducer函数
function reducer ( state = initialState, action ) {}
// 获取状态
store.getState();
// 订阅状态同步视图
store.subscribe(function () {})
// 触发action
store.dispatch({ type: 'description' })
3.在react中使用redux解决的问题
3.1在react中不使用redux遇到的问题
在React中组件通信的数据流是单项的,顶层组件可以通过prop属性向下层组件传递数据,而下层组件不能向上层组件传递数据,要实现下层组件修改数据,需要上层组件传递修改数据的方法到下层组件。当项目越来越大的时候,组件之间传递数据变得越来越困难。
3.2在react项目中加入Redux的好处
使用Redux管理数据,由于Store独立于组件,使得数据管理独立于组件,解决了组件与组件之间传递数据困难的问题
4.Provider组件和connect方法
provider组件和connect方法都是react-redux提供的
4.1 provider组件
provider组件的作用是让创建出来的store放在一个全局的地方,放在一个组件能够够得着的地方,provider需要传入一个值,传入的值就是创建出来的store
provider组件应该包裹项目所有的组件,他应该是最外层的组件
// 通过provider组件 将 store 放在了全局的组件可以够的到的地方
<Provider store={store}><App/></Provider>,
4.2 connect方法
connect 方法会帮助我们订阅store 当store中的状态发生更改的时候 会帮助我们重新渲染组件
connect 方法可以让我们获取store中的状态 将状态通过组件的props属性映射给组件
connect 方法可以让我们获取 dispatch 方法
const mapStateToProps = state => ({
count: state.counter.count
});
const mapDispatchToProps = dispatch => bindActionCreators(couterActions, dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
export const increment = payload => ({type: INCREMENT, payload});
export const decrement = payload => ({type: DECREMENT, payload});
connect方法被调用后会返回一个方法,再次调用第二个参数中传入当前的组件,传入当前组建的原因是connect要知道当store发生变化的时候,视图要更新哪一个组件。并且connect还会把store中的状态映射到组件的props中传入当前组件的原因也是他要知道映射到哪一个组件的props中
调用connect传入的第一个方法,他的参数是store中的状态,他返回一个对象,这个返回的对象里面的所有的参数都会映射到组建的props中
connect方法的第二个参数是将store中dispatch的方法映射到props中
bindActionsCreators方法:他是一个生成actions的方法 他的第一个参数是actions的函数名字,就是需要触发的函数他返回一个对象,对象中第一个参数是type字符串第二个参数是载荷;第二个参数是dispatch,最后他会返回一个对象,就是第一个参数和第二个参数拼接而成的方法,例如:
increment() {
dispatch({type: 'increment'})
}
4.3 combineReducers方法
这个方法要求我们传递一个对象,这个对象就是状态对象,里面存放的值是reducers返回的值
import { combineReducers } from 'redux';
import CounterReducer from './counter.reducer';
import ModalReducer from './modal.reducer';
// { counter: { count: 0 }, model: { show: false } }
export default combineReducers({
counter: CounterReducer,
modal: ModalReducer
})
二、Redux中间件
1、什么是中间件?
中间件允许我们扩展和增强redux应用程序,他的扩展和增强体现在action的处理能力上,之前触发action是直接被reducer处理了,再加入了action之后,这个action会优先被中间件处理,当中间件处理完这个action之后,再把处理完的aciton传递给reducer,让reducer继续处理这个action
2加入了中间件Redux的工作流程
3、开发Redux中间件
开发中间件模板代码,他是函数柯里化的代码
export default store => next => action => {
console.log('test中间件被执行了');
next(action)
}
其中store就是整体实例化的对象里面有state有dispatch,action是组件所触发的那个action对象,next方法是在中间件代码执行完之后调用,调用next方法的原因就是把当前处理完的action传递给reducer或者说是传递给下一个中间件
4、注册中间件
中间件在开发完成以后只有被注册才能在Redux的工作流程中生效
import { createStore, applyMiddleware } from "redux";
import logger from './middleware/logger';
createStore(reducer, applyMiddleware(
logger
))
applyMiddleware这个函数的作用就是注册中间件,将applyMiddleware这个方法的调用放在createStore的第二个参数中,applyMiddleware的调用中传入的就是自己写好的中间件
中间件拥有执行顺序,他的执行顺序取决于注册中间件时的顺序
中间件开发时可以穿action对象 也可以传函数,当前中间件函数在调用你传递进来的函数时 要将dispatch方法传递过去,dispatch在第一个函数的形参store中,一般aciton是一个对象,现在需要传递的是一个函数例子:
// 一般形式
export const increment = payload => ({type: 'increment', payload})
// 传递函数形式actions
export const increment_async => payload => dispatch => {
setTimeout(() => {
dispatch(increment(payload))
} ,2000)
}
他先接受一个载荷然后返回一个函数接受中间件传入的dipatch,在其中进行异步操作,dispatch触发上面增加方法的actions
5、Redux-thunk和Redux-saga(常用中间件)
这两个中间件的作用是一样的都是让我们可以在中间件中加入异步代码
redux-saga解决的问题是可以将异步操作从Action Creator 文件中抽离出来,放在一个单独文件中
使用redux-saga的第一步是注册sagaMiddleware,将sageMiddleware传入applyMiddleware
redux-saga的使用案例:
import { takeEvery, put, delay } from 'redux-saga/effects';
function* load_posts () {
const { data } = yield axios.get('/api/posts.json')
yield put(load_posts_success(data))
}
export default function* postSaga () {
yield takeEvery(LOAD_POSTS, load_posts)
}
redux-saga重要的两个参数,第一个takeEvery方法:当组件去触发一个action的时候,在saga文件中我们可以通过takeEvery这个方法去接受这个action,引入的第二个方法put是用来触发另外一个action的,我们需要用put方法触发另外一个action,帮助我们把异步处理的结果传递给reducer,让reducer把这个数据保存在store,
redux-sage要求默认导出一个generator函数,里面调用takeEvery去接收action,takeEvery的第一个参数是action的type字符串,第二个参数是接收完type要处理的方法是一个函数,可以直接写函数也可以写函数名
第二个形参传入的函数他接收了一个参数是,接受的参数就是action,也就是传入的action
启动sage:我们必须调用 sageMiddleware的run方法去启动编写好的saga
在saga中延时操作是不能用setTimeout的,必须使用saga提供的方法delay,他接收的参数就是延迟的时间
6、Redux-action(常用中间件)
redux-actions解决的问题:redux流程中大量的样板代码读写很痛苦,使用redux-actions可以简化Action和Reducer的处理
创建Action
import { createAction } from 'redux-actions';
const increment_action = createAction('increment')
const decrement_action = createAction('decrement')
之前我们是自己写actioncreator函数,现在要是用createAction创建这个函数,里面传入的值是就是type里的字符串,他的返回值就是之前自己写的actioncreator函数
创建Reducer
import { handleActions as createReducer } from 'redux-actions';
import { increment_action, decrement_action } from '';
const initialState = {count: 0};
const counterReducer = createReducer({
[increment_action]: (state, action) => ({count: state.count + 1}),
[decrement_action]: (state, action) => ({count: state.count - 1})
}, initialState);
export default counterReducer
引入的handleActions方法的作用是生成创建reducer函数,这里方便理解取了别名createReducer,他的第一个参数是传入一个对象,对象中的键是生成的action,因为他是变量所以要用方括号引起来,他的值是一个函数,参数中有state和action,返回新的state值;第二个参数存放的是初始state值。
在创建action的时候不用写payload,在调用的时候传递参数的时候redux-action中间件会自动把参数传进reducer,在createReducer中会把action自动传入