简介
- Redux 是一个有用的架构
- Redux 的适用场景:多交互、多数据源
工作流程图
action
用户请求
//发出一个action
import { createStore } from 'redux';
const store = createStore(fn);//其中的type属性是必须的,表示 Action 的名称。其他属性可以自由设置
const action = {type: 'ADD_TODO',data: 'Learn Redux'
};store.dispatch(action);
Reducer
状态机
Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。
Reducer 是纯函数,就可以保证同样的State,必定得到同样的 View。但也正因为这一点,Reducer 函数里面不能改变 State,必须返回一个全新的对象
const defaultState = 0;
const reducer = (state = defaultState, action) => {switch (action.type) {case 'ADD':return {...state,data: action.data}default: return state;}
};
Recucer的拆分
//index
import {combineReducers} from 'redux';
import proIndex from './proIndex';
import product from './product'
export default combineReducers({proIndex,product,
});//product
import actions from '../action/index'
import {getDocMenu} from "../action/user/product";const {GET_PRODUCT_DOCUMENT_SUCCESS
} = actions;export default (state = {},action) =>{switch (action.type) {case GET_PRODUCT_DOCUMENT_SUCCESS:return{...state,getDocMenu: action.data,}default:return state;}
}//proIndex
import actions from '../action/index';const {GET_SERVICE_CLASSIFICATION_SUCCESS,GET_SERVICE_SUBJECT_SUCCESS,
} = actions;export default (state = {},action) => {switch (action.type) {case GET_SERVICE_CLASSIFICATION_SUCCESS:return {...state,getServiceClass: action.data,};case GET_SERVICE_SUBJECT_SUCCESS:return {...state,getServiceSubject: action.data,};default:return state;}
};
store
数据仓库
import { createStore } from 'redux'
import todoApp from './reducers'
//创建store仓库
const store = createStore(todoApp)
//createStore方法还可以接受第二个参数(),表示 State 的最初状态。这通常是服务器给出的(window.STATE_FROM_SERVER就是整个应用的状态初始值)
const store = createStore(todoApp, window.STATE_FROM_SERVER)//引入action
import {addTodo,toggleTodo,setVisibilityFilter,VisibilityFilters
} from './actions'//打印当前状态
console.log(store.getState())// 订阅state变化
// subscribe()方法返回一个函数用于取消监听
const unsubscribe = store.subscribe(() => console.log(store.getState()))// 发出一些action
store.dispatch(addTodo('Learn about actions'))
store.dispatch(addTodo('Learn about reducers'))
store.dispatch(addTodo('Learn about store'))
store.dispatch(toggleTodo(0))
store.dispatch(toggleTodo(1))
store.dispatch(setVisibilityFilter(VisibilityFilters.SHOW_COMPLETED))//取消监听状态更新
unsubscribe()
配置中间件
import { createStore } from 'redux'
import reducer from '../reducer/index'
import thunk from 'redux-thunk'
import promise from 'redux-promise'
import logger from 'redux-logger'const store = createStore(reducer,applyMiddleware(thunk, promise, logger)
);
redux-thunk
store.dispatch()只能传入一个action对象,redux-thunk中间件则将其扩展为一个方法
//配置
import { createStore } from 'redux'
import reducer from '../reducer/index'
import thunk from 'redux-thunk'const store = createStore(reducer,applyMiddleware(thunk)
);//使用
export function getDocMenu(query='') {return async(dispatch) => {try {const data = (await axios(`${baseUrl}doc.do?${Qs.stringify(query)}`)).data;//这里的dispatch相当于store.dispatchdispatch({type: GET_PRODUCT_DOCUMENT_SUCCESS,data: data})}catch(error){dispatch({type: GET_PRODUCT_DOCUMENT_FAILURE,error: new Error('获取文档菜单失败')})}}
}
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)//使用
// action creators
export function GET_USERS(users) {return { type: RECEIVE_USERS, data }
}export function GET_ERROR(error) {return { type: FETCH_USERS_ERROR, data }
}export function Begin_GET_POSTS() {return { type: BEGIN_GET_POSTS }
}//saga.js
import { takeEvery } from 'redux-saga';
import { call, put } from 'redux-saga/effects';
import axios from 'axios';
import { BEGIN_GET_POSTS, GET_POSTS, GET_POSTS_ERROR } from '../reducers';// worker saga
function* showPostsAsync(action) {try {const response = yield call(axios.get, 'https://jsonplaceholder.typicode.com/posts');yield put({type: GET_POSTS,data: response.data});} catch(e) {yield put({type: GET_ERROR,error: new Error('some error')});}
}// wacther saga
function* watchGetPosts() {yield takeEvery(BEGIN_GET_POSTS, showPostsAsync);
}// root saga
export default function* rootSaga() {yield watchGetPosts()
} //user.jscomponentWillMount() {this.props.dispatch(Begin_GET_POSTS());
}