关于Redux
思考
首先判断是否需要用redux
- 用户的使用方式复杂
- 不同身份的用户有不同的使用方式(比如普通用户和管理员)
- 多个用户之间可以协作
- 与服务器大量交互,或者使用了WebSocket
- View要从多个来源获取数据
总之就是多交互,多数据源
从组件的角度看,以下场景可以考虑用redux
- 某个组件的状态,需要共享
- 某个状态需要在任何地方都可以拿到
- 一个组件需要改变全局状态
- 一个组件需要改变另一个组件的状态
基本流程
确定使用redux后,先过一下基本流程
- 创建store
- 给仓库store传入对应的数据源(reducer)
- 在对应的页面引入store,利用store.getState()初始化组件的state数据
- 操作改变store里的数据,定义action(type:,value:),将action传入,利用store.dispatch通知store数据变动
- reducer接受action,根据传入的type,将原数据的value改变,返回state
- 一旦返回新的state,将触发store.subscribe(func),定义func方法,重新setstate数据源,更新页面
创建仓库store(管理员)
import {createStore} from 'redux';
import reducer from './reducer.js'; // 将系统return出去的state拿到
const store = createStore(reducer); // 将定义好的数据(defaultState),交给了仓库store
export default store;
方法
方法 | 作用 |
---|---|
store.getState() | 可以获取store内部的数据(defaultState) |
store.dispatch(action) | 将要改变的数量类型(type)和内容(value)传给store |
store.subscribe(function) | 感知到store里面的数据变化,触发方法 |
reducer (系统)
const defaultState = {};
export default(state = defaultState, action) =>{
if(action.type === 'type'){
const newState = JSON.parse(JSON.stringify(state)) // 复制一个state
newState.value = action.value;
return newState
}
return state
}
state默认仓库初始为空,action = {type:’’, value:’’},reducer可以接受state,但是绝不能修改state
reducer拆分
import {combineReducers} from 'redux';
import { user} from './userStore';
import {chatUser} from './chatStore';
import {chat} from './chatMsgStore';
export default combineReducers({
user,
chatUser,
chat,
})
上面的代码通过combineReducers方法将三个子 Reducer 合并成一个大的函数。
中间件
中间件就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能。
(1)createStore方法可以接受整个应用的初始状态作为参数,那样的话,applyMiddleware就是第三个参数了。
const store = createStore(
reducer,
initial_state,
applyMiddleware(logger)
);
applyMiddlewares:它是 Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行
(2)中间件的次序有讲究。
const store = createStore(
reducer,
applyMiddleware(thunk, promise, logger)
);
有的中间件有次序要求,使用前要查一下文档。比如,logger就一定要放在最后,否则输出结果会不正确。
常用中间件的介绍
redux-thunk
简单来说,就是支持我们action返回一个函数,方便进行异步操作
export function update(data){
return dispatch=>{
axios.post('/user/update',data)
.then(res=>{
if(res.status === 200 && res.data.code ===0){
dispatch(action)
}else{
dispatch(action)
}
})
}
}
优点
使用简单,易上手
缺点
不易维护,可扩展性差
redux-saga
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import reducer from './reducers'
import mySaga from './sagas'
// create the saga middleware
const sagaMiddleware = createSagaMiddleware()
// mount it on the Store
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
)
// then run the saga
sagaMiddleware.run(mySaga)
// render the application
新建一个saga.js
这里只是举了最简单的例子,想要深入了解,地址
import { put, takeEvery } from 'redux-saga/effects';
func(){
let res = yield axios.post('/user/update',data);
let action = actionCreator(res.data); // 返回一个对象
yield put(action) // 注意,这里put相当于dispatch
}
function* mySaga() {
yield takeEvery("USER_FETCH_REQUESTED", func);
}
export default mySaga;
优点
(1)集中处理了所有的异步操作,异步接口部分一目了然
(2)action是普通对象,这跟redux同步的action一模一样
(3)通过Effect,方便异步接口的测试
(4)通过worker 和watcher可以实现非阻塞异步调用,并且同时可以实
现非阻塞调用下的事件监听
(5) 异步操作的流程是可以控制的,可以随时取消相应的异步操作。
缺点
学习成本较高
react-redux
import {connect} from 'react-redux';
使用Provider包裹住对应的子组件,接受属性store
import {connect} from 'react-redux';
connect连接子组件和store
connect(mapStateToProps, mapDispatchToProps)(Login);
mapStateToProps
const mapStateToProps = (state) => {
return {
健名: state.健名
}
}
此方法,是将store里的数据映射到props里,你可以简单理解为store.getState()
mapDispatchToProps
const mapDispatchToProps = (dispatch) => {
return {
func(){
dispatch(action)
}
}
}
func
是组件调用,用来改变store里的数据