redux
一、 基础
1. import
import { createStore } from 'redux'; const store = createStore(fn);
2. getState
//获取当前时刻的state
const state = store.getState();
3. action
//action对象,type必需
const action = { type: 'ADD_TODO', payload: 'Learn Redux'};
4. action creator
//生成action creator,方便action书写
const ADD_TODO = ‘添加 TODO’;
function addTodo(text) { return { type: ADD_TODO, text } } const action = addTodo('Learn Redux');
5. dispatch发出action
//View 发出 Action 的唯一方法dispatch
store.dispatch(addTodo('Learn Redux'));
6. reducer返回新state
//接受 Action 和当前 State 作为参数,返回一个新的 State
const reducer = function (state, action) { // … return new_state;};
const defaultState = 0; const reducer = (state = defaultState, action) => { switch (action.type) { case 'ADD': return state + action.payload; default: return state; }}; const state = reducer(1, { type: 'ADD', payload: 2});
7. 自动调用reducer
import { createStore } from 'redux'; const store = createStore(reducer);
上面代码中,createStore接受 Reducer 作为参数,生成一个新的 Store。以后每当store.dispatch发送过来一个新的 Action,就会自动调用 Reducer,得到新的 State。
为什么这个函数叫做 Reducer 呢?因为它可以作为数组的reduce方法的参数。请看下面的例子,一系列 Action 对象按照顺序作为一个数组。
const actions = [ { type: 'ADD', payload: 0 }, { type: 'ADD', payload: 1 }, { type: 'ADD', payload: 2 } ];
const total = actions.reduce(reducer, 0); // 3
8. subscribe监听
//Store 允许使用store.subscribe方法设置监听函数,一旦 State 发生变化,就自动执行这个函数。
import { createStore } from 'redux'; const store = createStore(reducer); store.subscribe(listener);
store.subscribe方法返回一个函数,调用这个函数就可以解除监听。
let unsubscribe = store.subscribe(() => console.log(store.getState()) ); unsubscribe();
9. Store 的实现
- getState()
- dispatch()
- subscribe()
import { createStore } from 'redux'; let { subscribe, dispatch, getState } = createStore(reducer);
createStore方法还可以接受第二个参数,表示 State 的最初状态。这通常是服务器给出的。
let store = createStore(todoApp, window.STATE_FROM_SERVER)
示例:
const createStore = (reducer) => { let state; let listeners = []; const getState = () => state; const dispatch = (action) => { state = reducer(state, action); listeners.forEach(listener => listener()); }; const subscribe = (listener) => { listeners.push(listener); return () => { listeners = listeners.filter(l => l !== listener); } }; dispatch({}); return { getState, dispatch, subscribe }; };
10.reducer拆分
可以把所有子 Reducer 放在一个文件里面,然后统一引入。
import { combineReducers } from 'redux' import * as reducers from './reducers' const reducer = combineReducers(reducers)
二、 中间件
1. 用法
日志中间件,就有现成的redux-logger模块
import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';
const logger = createLogger();
const store = createStore(
reducer,
applyMiddleware(logger)
);
createStore有三个参数,中间件有次序要求,比如,logger就一定要放在最后
const store = createStore(
reducer,
initial_state,
applyMiddleware(thunk, promise, logger)
);
applyMiddlewares是 Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行,最后执行store.dispatch。
2. 异步操作中间件
reduc-thunk
redux-thunk中间件,改造store.dispatch,使得后者可以接受函数作为参数
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducers'; // Note: this API requires redux@>=3.1.0
const store = createStore( reducer, applyMiddleware(thunk));
fetchPosts是一个Action Creator(动作生成器),返回一个函数.
const fetchPosts = postTitle => (dispatch, getState) => { dispatch(requestPosts(postTitle)); return fetch(`/some/API/${postTitle}.json`) .then(response => response.json()) .then(json => dispatch(receivePosts(postTitle, json))); }; }; // 使用方法一 store.dispatch(fetchPosts('reactjs')); // 使用方法二 store.dispatch(fetchPosts('reactjs')).then(() => console.log(store.getState()));
redux-promise
import { createStore, applyMiddleware } from 'redux'; import promiseMiddleware from 'redux-promise'; import reducer from './reducers'; const store = createStore( reducer, applyMiddleware(promiseMiddleware) );
这时,Action Creator 有两种写法。写法一,返回值是一个 Promise 对象。
const fetchPosts = (dispatch, postTitle) => new Promise(function (resolve, reject) { dispatch(requestPosts(postTitle)); return fetch(`/some/API/${postTitle}.json`) .then(response => { type: 'FETCH_POSTS', payload: response.json() }); });
写法二,Action 对象的payload属性是一个 Promise 对象。这需要从redux-actions模块引入createAction方法,并且写法也要变成下面这样。
import { createAction } from 'redux-actions'; class AsyncApp extends Component { componentDidMount() { const { dispatch, selectedPost } = this.props // 发出同步 Action dispatch(requestPosts(selectedPost)); // 发出异步 Action dispatch(createAction( 'FETCH_POSTS', fetch(`/some/API/${postTitle}.json`) .then(response => response.json()) )); }
三、 react-redux
React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)
1. connect
import { connect } from 'react-redux' const VisibleTodoList = connect( mapStateToProps, mapDispatchToProps)(TodoList)
mapStateToProps
负责输入逻辑,即将state映射到 UI 组件的参数(props),
mapDispatchToProps
负责输出逻辑,即将用户对 UI 组件的操作映射成 Action。
2. provider
React-Redux 提供Provider组件,可以让容器组件拿到state。
import { Provider } from 'react-redux' import { createStore } from 'redux' import todoApp from './reducers' import App from './components/App' let store = createStore(todoApp); render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
3. React-Router 路由库
const Root = ({ store }) => ( <Provider store={store}> <Router> <Route path="/" component={App} /> </Router> </Provider> );