npm install --save redux
# 补充包
# 也许你还要和react一起使用,并且需要开发工具
npm install --save react-redux
npm install --save-dev redux-devtools
import { createStore } from 'redux'
/**
* 这是一个reducer,它是一个具有(state,action)=>状态签名的纯函数。
* 它描述了动作如何将状态转换为下一个状态。
* 状态的形状取决于你:它可以是一个基元,一个数组,一个对象,
* 甚至是Immutable.js数据结构。 唯一重要的部分是你应该
* 不改变状态对象,但如果状态改变则返回一个新的对象。
* 在这个例子中,我们使用`switch`语句和字符串,但是你可以使用一个帮助器
* 遵循不同的约定(如功能图),如果它适合你的项目。
*/
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
// 创建一个持有应用状态的Redux store。
// 他的api { subscribe, dispatch, getState }.
let store = createStore(counter)
// 你可以通过subscribe()来更新ui来响应状态的改变。
// 通常你会使用视图绑定库 (比如:React-Redux) 比起直接用 subscribe() 。
// 但是,将当前状态保存在localStorage中也可能非常方便。
store.subscribe(() =>
console.log(store.getState())
)
// 改变内部状态的唯一方法是发送一个action。
// 这些动作可以被序列化,记录或存储,并在以后重播。
store.dispatch({ type: 'INCREMENT' })
// 1
store.dispatch({ type: 'INCREMENT' })
// 2
store.dispatch({ type: 'DECREMENT' })
您不需要直接改变状态,而是使用称为操作的简单对象指定想要发生的突变。然后编写一个称为reducer的特殊函数来决定每个操作如何转换整个应用程序的状态。
如果您用过Flux,那么您需要了解一个重要的差异。 Redux没有分派器或支持许多store。相反,只有一个store具有单一根reducer函数。随着您的项目的扩展,您不必添加store,而是将根reducer分解为更小的reducer,并独立运行于状态树的不同部分。这就好像React应用程序中只有一个根组件,但它由许多小组件组成。
这种体系结构可能看起来像一个反应器应用程序的矫枉过正,但这种模式的美妙之处在于它如何适应大型复杂的应用程序。它还支持非常强大的开发者工具,因为可以追踪引发它的操作的每个变异。您可以记录用户会话并通过重播每一个动作来重现它们。
npm install --save redux-thunk
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
// Note: redux@>=3.1.0
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
function increment() {
return {
type: INCREMENT_COUNTER
};
}
// 异步
function incrementAsync() {
return dispatch => {
setTimeout(() => {
// 用dispatch可以处理同步和异步的action
dispatch(increment());
}, 1000);
};
}
// 一个action创建者返回一个函数去实现条件分发
function incrementIfOdd() {
return (dispatch, getState) => {
const { counter } = getState();
if (counter % 2 === 0) {
return;
}
dispatch(increment());
};
}
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
// Note: redux@>=3.1.0
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
function fetchSecretSauce() {
return fetch('https://www.google.com/search?q=secret+sauce');
}
// 正常action的创建
// 他们返回的action可以在没有任何中间件的情况下派发
// 然而他们只能表达事实,而不是异步流程。
function makeASandwich(forPerson, secretSauce) {
return {
type: 'MAKE_SANDWICH',
forPerson,
secretSauce
};
}
function apologize(fromPerson, toPerson, error) {
return {
type: 'APOLOGIZE',
fromPerson,
toPerson,
error
};
}
function withdrawMoney(amount) {
return {
type: 'WITHDRAW',
amount
};
}
// 甚至没有中间件你可以分发action.
store.dispatch(withdrawMoney(100));
// 当你需要使用异步操作比如api的调用或路由转换
// thunk函数返回一个函数
function makeASandwichWithSecretSauce(forPerson) {
// 反转控制
// 返回一个接受`dispatch`的函数,以便稍后分发。
// Thunk 中间件知道如何将异步action转换为action
return function (dispatch) {
return fetchSecretSauce().then(
sauce => dispatch(makeASandwich(forPerson, sauce)),
error => dispatch(apologize('The Sandwich Shop', forPerson, error))
);
};
}
// Thunk 中间件让我们分发thunk异步action
// 就好像自己的action一样
store.dispatch(
makeASandwichWithSecretSauce('Me')
);
// 它甚至需要关心thunk的返回值
// 对于dispatch, 我们只有声明一个promise对象并返回他们.
store.dispatch(
makeASandwichWithSecretSauce('My wife')
).then(() => {
console.log('Done!');
});
// 事实上,我们通过编写dispacth的action。
// 来自其他action创建者创建的action和 异步actiuon,
// 我们可以通过promise构建控制流
function makeSandwichesForEverybody() {
return function (dispatch, getState) {
if (!getState().sandwiches.isShopOpen) {
// 你不必返回promise对象,这是很便利的
// 因此调用者可以始终使用.then()函数来获取异步分发的结果
return Promise.resolve();
}
// 我们可以分发普通对象action和其他thunk,
// 这使得我们可以在单个流程中组合异步操作
return dispatch(
makeASandwichWithSecretSauce('My Grandma')
).then(() =>
Promise.all([
dispatch(makeASandwichWithSecretSauce('Me')),
dispatch(makeASandwichWithSecretSauce('My wife'))
])
).then(() =>
dispatch(makeASandwichWithSecretSauce('Our kids'))
).then(() =>
dispatch(getState().myMoney > 42 ?
withdrawMoney(42) :
apologize('Me', 'The Sandwich Shop')
)
);
};
}
// 这对服务端渲染非常有用,因为我们可以等待服务器的响应。
// 知道服务端响应的数据完成然后才开始同步渲染应用。
store.dispatch(
makeSandwichesForEverybody()
).then(() =>
response.send(ReactDOMServer.renderToString())
);
//我们也可以在一个组件中分发一个异步的thunk action。
// 任何时间它的props的改变将加载缺少的数据
import { connect } from 'react-redux';
import { Component } from 'react';
class SandwichShop extends Component {
componentDidMount() {
this.props.dispatch(
makeASandwichWithSecretSauce(this.props.forPerson)
);
}
componentWillReceiveProps(nextProps) {
if (nextProps.forPerson !== this.props.forPerson) {
this.props.dispatch(
makeASandwichWithSecretSauce(nextProps.forPerson)
);
}
}
render() {
return {this.props.sandwiches.join('mustard')}
}
}
export default connect(
state => ({
sandwiches: state.sandwiches
})
)(SandwichShop);
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument(api))
)
// 然后
function fetchUser(id) {
return (dispatch, getState, api) => {
// 你可以在这里使用api
}
}
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument({ api, whatever }))
)
// 然后
function fetchUser(id) {
return (dispatch, getState, { api, whatever }) => {
// 你可以在这里使用api和其他东西
}
}