还在学习中…
动机
随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。
管理不断变化的 state 非常困难。如果一个 model 的变化会引起另一个 model 变化,那么当 view 变化时,就可能引起对应 model 以及另一个 model 的变化,依次地,可能会引起另一个 view 的变化。
React-Redux 之store, action, reducer
react-redux组件处理
react-redux会将所有的组件分为两大类:UI组件和容器组件。
UI组件特征:
- 只负责UI的呈现, 不参与业务逻辑
- 没有状态(即不使用
this.state
这个变量) - 所有数据都由
this.props
提供的 - 不使用任何redux的API
容器组件特征:
- 负责管理数据和业务逻辑,不负责UI的呈现
- 带有内部状态
- 使用redux的API
总结一句话:UI组件只是负责UI的呈现,容器组件是负责管理数据和业务逻辑的。
connect高阶函数
react-redux规定所有的UI就是用户提供的,也就是
render
函数返回的代码,容器组件是由react-redux自动生成的,用户只需要负责页面展示,状态管理交给react-redux。
UI组件:
render() {
return (
<div>
<button type="submit" onClick={this.handleClick.bind(this)}>
添加
</button>
</div>
);
}
如何让一个普通的UI组件分为UI组件和容器组件?
使用react-redux的connect方法,ComA是用户自定义的UI组件,通过connect函数生成容器组件(
container
),当然这样的组件也只是多包裹了一层而已,还需要绑定数据和定义业务逻辑。
import { connect } from "react-redux";
const container = connect(mapStateToProps, mapStateDispatchToProps, mergeProps?)(ComA);
export default container;
mapStateToProps()
mapStateToProps()
它是一个函数,它的作用就是建立一个state
对象到props
对象的映射关系,这个函数的返回值是一个{key: value}对象。mapStateToProps()
会将redux的store(state)中的数据会作为props绑定到组件上。
const mapStateToProps = (state,ownProps) => {
// ownProps表示当前组件的props
// console.log(state);
return {
num: state.num, // 当前组件的props就多了一个num,值为store里面的num的值
};
};
个人理解组件代码:首先这是一个普通的UI组件,但是经过
connect
处理过后,就可以与store联系起来,然后通过connect的第一个参数mapStateToProps
将store的内容与当前组件的props
联系起来。从而达到了当store里面的数据更新了,当前组件也会随着改变。
mapStateDispatchToProps()
mapDispatchToProps
是connect函数的第二个参数,用来建立UI组件的参数到store.dispatch
方法的映射,它定义了用户的操作应该当做action传递给store。
const mapStateDispatchToProps = (dispatch, ownProps) => {
// ownProps表示当前组件的props
return {
sendAddAction() {
dispatch({ // dispatch分发动作, reducer进行处理
type: "add_action",
value: 2,
});
},
};
};
个人理解组件代码:
mapStateDispatchToProps
中定义一个方法,等着用户去触发,一旦触发了就会执行dispatch
从而将type和value发送给reducer
,reducer
收到通知过后,根据type类型,从而执行相应的逻辑操作。
mergeProps()
获取
mapStateToProps
,mapStateDispatchToProps
以及当前组件props属性
const mergeProps = (...arg) => {
console.log(arg); // stateProps, dispatchProps, ownProps
};
Provider组件
connect()
函数生成了容器组件过后,需要让容器组件拿到state对象,才能生成UI组件的参数。Provider只要是被他包裹的容器组件都可以拿到state对象。
// store/index.js文件
import { createStore } from "redux";
import reducers from "../reducer";
export default createStore(reducers);
// App.js文件
import store from "./store";
function App() {
return (
<Provider store={store}>
<ComA></ComA>
<ComB></ComB>
</Provider>
);
}
完整实例,计数器
- 初始化操作,编写store,reducer
reducer不允许直接修改state, 修改复杂类型可使用JSON.parse(JSON.stringify())进行深拷贝, 在新对象身上修改, 最后返回.
-
编写组件A
import React, { Component } from "react"; import { connect } from "react-redux"; class ComA extends Component { constructor(props) { super(props); } handleClick() { this.props.sendAddAction(); } render() { return ( <div> <button type="submit" onClick={this.handleClick.bind(this)}> 添加 </button> </div> ); } } // 第二个参数, 是发送数据, 也就是页面中触发一个动作, // 进而触发函数, 函数就会向reducer发送一个action, 表示要操作state了; const mapStateDispatchToProps = (dispatch) => { return { sendAddAction() { dispatch({ type: "add_action", value: 2, }); }, }; }; const container = connect(null, mapStateDispatchToProps)(ComA); export default container;
-
编写组件B
import React, { Component } from "react"; import { connect } from "react-redux"; class ComB extends Component { render() { console.log(this.props); return ( <div> <h1>{this.props.num}</h1> </div> ); } } const mapStateToProps = (state) => { // console.log(state); return { num: state.num, }; }; export default connect(mapStateToProps)(ComB);
-
App.js
import "./App.css"; import { Provider } from "react-redux"; import ComA from "./page/comA"; import ComB from "./page/comB"; // *************************************** import store from "./store"; // *************************************** function App() { return ( <Provider store={store}> <ComA></ComA> <ComB></ComB> </Provider> ); } export default App;
-
页面截图
整个操作流程:
- 开始页面就显示store里面的num,也就是第三个步骤的
{this.props.num}
,因为connect
处理过后,就可以与store联系起来,进而可以通过props获取到store里面的num。- 用户执行了点击操作(步骤二),发送了一个type为’add_action’的操作,接着传递给reducer,reducer根据type来执行操作也就是步骤一。
- 所有的前提就是组件要有store(步骤四),因此Provider这个步骤尤为重要。