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>
);
