Redux 和 React-redux 并非同一个东西。react
Redux 是一种架构模式(Flux 架构的一种变种),它不关注你到底用什么库,你能够把它应用到 React 和 Vue,甚至跟 jQuery 结合都没有问题。redux
而 React-redux 就是把 Redux 这种架构模式和 React.js 结合起来的一个库,就是 Redux 架构在 React.js 中的体现。bash
模块(组件)之间须要共享数据,可是每一个人均可以修改它,一个能够被不一样模块任意修改共享的数据状态就是魔鬼,一旦数据能够任意修改,全部对共享状态的操做都是不可预料的,数据可能被任意修改致使不可预料的结果。架构
咱们定义一个函数,叫 dispatch,它专门负责数据的修改:app
function dispatch (action) {
switch (action.type) {
case 'UPDATE_TITLE_TEXT':
appState.title.text = action.text
break
case 'UPDATE_TITLE_COLOR':
appState.title.color = action.color
break
default:
break
}
}
复制代码
全部对数据的操做必须经过 dispatch 函数。它接受一个参数 action,这个 action 是一个普通的 JavaScript 对象,里面必须包含一个 type 字段来声明你到底想干什么。异步
const store = createStore(appState, stateChanger)
store.subscribe(() => renderApp(store.getState())) // 监听数据变化
renderApp(store.getState()) // 首次渲染页面
store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: '《React.js 小书》' }) // 修改标题文本
store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' }) // 修改标题颜色
复制代码
经过 store.getState 咱们获取共享状态,并且咱们约定只能经过 store.dispatch 修改共享状态。store 也容许咱们经过 store.subscribe 监听数据数据状态被修改了,而且进行后续的例如从新渲染页面的操做。ide
createStore 接受一个叫 reducer 的函数做为参数,这个函数规定是一个纯函数,它接受两个参数,一个是 state,一个是 action。函数
reducer 是不容许有反作用的。你不能在里面操做 DOM,也不能发 Ajax 请求,更不能直接修改 state,它要作的仅仅是 —— 负责初始 state,和根据 state 和 action 计算具备共享结构的新的 state。学习
const reducer = (state = {count: 0}, action) => {
switch (action.type){
case 'INCREASE': return {count: state.count + 1};
case 'DECREASE': return {count: state.count - 1};
default: return state;
}
}
const actions = {
increase: () => ({type: 'INCREASE'}),
decrease: () => ({type: 'DECREASE'})
}
const store = createStore(reducer);
store.subscribe(() =>
console.log(store.getState())
);
store.dispatch(actions.increase()) // {count: 1}
store.dispatch(actions.increase()) // {count: 2}
store.dispatch(actions.increase()) // {count: 3}
复制代码
经过 reducer 建立一个 store,每当咱们在 store 上 dispatch 一个 action,store 内的数据就会相应地发生变化。ui
建立store的时候,要先建立reducer,把reducer传递进store下的index.js reducer里放的就是存放的数据
reducer能够接收state,可是毫不能修改state
一、store必须是惟一的
二、只有store可以改变本身的内容,reducer不能改
三、reducer必须是纯函数(给定固定的输入,就必定会有给定的输出,return的值是必定的)即不能有异步操做,也不能有关于时间定时器之类的操做
store.dispatch:派发action,帮助传递给store
store.getState:获取store中的数据
store.subscribe:监听数据的改变,触发监听回调
首先在最外层容器中,把全部内容包裹在 Provider 组件中,将以前建立的 store 做为 prop 传给 Provider。
const App = () => {
return (
<Provider store={store}>
<Comp/>
</Provider>
)
};
复制代码
Provider 内的任何一个组件(好比这里的 Comp),若是须要使用 state 中的数据,就必须是「被 connect 过的」组件——使用 connect 方法对「你编写的组件(MyComp)」进行包装后的产物。
class MyComp extends Component {
// content...
}
const Comp = connect(...args)(MyComp);
复制代码
可见,connect 方法是重中之重。
connect() 接收四个参数,它们分别是 mapStateToProps,mapDispatchToProps,mergeProps和options。
这个函数容许咱们将 store 中的数据做为 props 绑定到组件上。
const mapStateToProps = (state) => {
return {
count: state.count
}
}
复制代码
这个函数的第一个参数就是 Redux 的 store,咱们从中摘取了 count 属性。由于返回了具备 count 属性的对象,因此 MyComp 会有名为 count 的 props 字段。
class MyComp extends Component {
render(){
return <div>计数:{this.props.count}次</div>
}
}
const Comp = connect(...args)(MyComp);
复制代码
固然,你没必要将 state 中的数据原封不动地传入组件,能够根据 state 中的数据,动态地输出组件须要的(最小)属性。
const mapStateToProps = (state) => {
return {
greaterThanFive: state.count > 5
}
}
复制代码
函数的第二个参数 ownProps,是 MyComp 本身的 props。有的时候,ownProps 也会对其产生影响。好比,当你在 store 中维护了一个用户列表,而你的组件 MyComp 只关心一个用户(经过 props 中的 userId 体现)。
const mapStateToProps = (state, ownProps) => {
// state 是 {userList: [{id: 0, name: '王二'}]}
return {
user: _.find(state.userList, {id: ownProps.userId})
}
}
class MyComp extends Component {
static PropTypes = {
userId: PropTypes.string.isRequired,
user: PropTypes.object
};
render(){
return <div>用户名:{this.props.user.name}</div>
}
}
const Comp = connect(mapStateToProps)(MyComp);
复制代码
当 state 变化,或者 ownProps 变化的时候,mapStateToProps 都会被调用,计算出一个新的 stateProps,(在与 ownProps merge 后)更新给 MyComp。
这就是将 Redux store 中的数据链接到组件的基本方式。
connect 的第二个参数是 mapDispatchToProps,它的功能是,将 action 做为 props 绑定到 MyComp 上。
const mapDispatchToProps = (dispatch, ownProps) => {
return {
increase: (...args) => dispatch(actions.increase(...args)),
decrease: (...args) => dispatch(actions.decrease(...args))
}
}
class MyComp extends Component {
render(){
const {count, increase, decrease} = this.props;
return (<div>
<div>计数:{this.props.count}次</div>
<button onClick={increase}>增长</button>
<button onClick={decrease}>减小</button>
</div>)
}
}
const Comp = connect(mapStateToProps, mapDispatchToProps)(MyComp);
复制代码
因为 mapDispatchToProps 方法返回了具备 increase 属性和 decrease 属性的对象,这两个属性也会成为 MyComp 的 props。
如上所示,调用 actions.increase() 只能获得一个 action 对象 {type:'INCREASE'},要触发这个 action 必须在 store 上调用 dispatch 方法。diapatch 正是 mapDispatchToProps 的第一个参数。可是,为了避免让 MyComp 组件感知到 dispatch 的存在,咱们须要将 increase 和 decrease 两个函数包装一下,使之成为直接可被调用的函数(即,调用该方法就会触发 dispatch)。
Redux 自己提供了 bindActionCreators 函数,来将 action 包装成直接可被调用的函数。
import {bindActionCreators} from 'redux';
const mapDispatchToProps = (dispatch, ownProps) => {
return bindActionCreators({
increase: action.increase,
decrease: action.decrease
});
}
复制代码
一样,当 ownProps 变化的时候,该函数也会被调用,生成一个新的 dispatchProps,(在与 statePrope 和 ownProps merge 后)更新给 MyComp。注意,action 的变化不会引发上述过程,默认 action 在组件的生命周期中是固定的。
以前说过,不论是 stateProps 仍是 dispatchProps,都须要和 ownProps merge 以后才会被赋给 MyComp。connect 的第三个参数就是用来作这件事。一般状况下,你能够不传这个参数,connect 就会使用 Object.assign 替代该方法。