下面这些东西是今年八月份实习过程中最让人头痛的一段历程。。特么就会那么点html、css、js还写不明白呢。咣咣来了一堆前端新技术。。。没办法这个行业遇到这种事情,硬着头皮也得上,印证了需要程序员需要快速学习的能力。就像一个网友说的 最爽的一件事,就是项目经理丢来一堆新东西,让你一周学完。。。不过那时候只是把数据流跑通了直接干活了。。具体细节不想看。。。因为不喜欢前端。当时就模仿人家的语法,把页面套路出来了。。。
下面是两个流程图来表示react在redux下的数据流动
这是当时鑫哥给开发小组的解释:
state就是数据,组件就是数据的呈现形式,action是动作,action是通过reducer来更新state的
我们可以做个形象的比喻,把 js 比喻成巴士,把 store,container,reducer 比喻为三个车站,再把 state 和 action 比喻成两种乘客。这是一趟环路巴士:
js巴士 从 store车站 出发,载上 state乘客 ,state乘客 到达某个 container车站 下车并把自己展示出来
过了一会,有一个 action乘客 上车了,js巴士 把 action乘客 送到 reducer车站,在这里 action乘客 和 state乘客 生了一个孩子 new state,js巴士把 new state 送回了 store车站(好像是人生轮回→_→)
然后在结合图看看好像确实那么回事,但是因为没有demo。只是理论上的认知,反正就是上车了!虽然大伙儿一脸懵逼。
用白话描述就是
一些网上学习资料:
http://reactjs.cn/react/docs/getting-started.html
http://www.runoob.com/nodejs/nodejs-tutorial.html
https://github.com/reactjs/react-router/blob/latest/docs/guides/Histories.md
http://react-guide.github.io/react-router-cn/docs/guides/basics/RouteMatching.html
http://www.cnblogs.com/lewis617/p/5145073.html
https://github.com/camsong/redux-in-chinese
http://cordova.apache.org/
http://adt.aicai.com/index.php/archives/179/
https://github.com/liangzhenghui/cordova-qdc-baidu-location
http://www.cnblogs.com/xianyulaodi/p/5314868.html
http://www.jb51.cc/article/p-ndouusrc-c.html
但是就是硬着头皮看了上面那些链接的教程, 没办法谁坚持不下来谁翻车。。
那么接下来我会解释一些上面名词的概念,以及在代码中他们究竟是怎么来相互玩耍的。不过下面我已经把业务代码剔除,行业原则嘛。
store
承接了react的state,store里面的数据是不可修改的,只能返回一个new state。
页面中所有的渲染操作所需数据来是从store拽下来的
store有四个方法。
getState: 获取应用当前State。
subscribe:添加一个变化监听器。
dispatch:分发 action。修改State。
replaceReducer:替换 store 当前用来处理 state 的 reducer。
常用的是dispatch,这是修改State的唯一途径
Provider
Provider这个模块是作为整个App的容器,原有的App Container的基础上再包上一层,它的工作很简单,就是接受Redux的store作为props,并将其声明为context的属性之一,子组件可以在声明了contextTypes之后可以方便的通过this.context.store访问到store。不过我们的组件通常不需要这么做,将store放在context里,是为了给下面的connect用的。
// config app root
const history = createHistory()
const root = (
<Provider store={store} key="provider">
<Router history={history} routes={routes} />
</Provider>
)
component
就是我们真正要渲染的组件,组件里面的数据是从store里面搞出来的,注意这个组件(一个文件)可以导入其他模块,比如这是个列表页,列表页可以拆分成两部分:分类和内容列表展示,那么这个模块就要导入import这两个组件,在render中渲染。组件中还会包含action的导入,因为要在组件中用store的dispatch方法,请求action去向服务器做请求。组件中也包含connect模块,这个模块是真正意义上的redux和react的连接了,component组件就是通过这个模块把数据从store上拽下来的,注意组件可以有constructor构造方法,里面做一些方法绑定和初始化参数默认值,并且这些默认值可以是不归redux的store所管理的,当时还巧妙地利用了这一特性。
"use strict";
import React from 'react';
import {connect} from 'react-redux'
//导入action模块
import {
request,request2,selectRestScrollTop
} from '../../../action/wandaochi/restListAction'
export default class ChiAnYi extends React.Component {
constructor(props) {
super(props);
this.handleUpdateRestsList2 = this.handleUpdateRestsList2.bind(this);
this.handleUpdateRestsList = this.handleUpdateRestsList.bind(this);
this.unmountType = 0;
this.activeColor = "#69D8C5";
this.defaultColor = " #898989";
}
componentWillReceiveProps(nextProps) {
}
//一系列生命周期方法.......
render() {
return (
<div>
</div>
);
}
function mapStateToProps(state) {
}
export default connect(mapStateToProps)(ChiAnYi);
connect
来仔细看一下这个connect
mapStateToProps 需要负责的事情就是 返回需要传递给子组件的State,然后connect会拿到返回的数据写入到react组件中,然后组件中就可以通过props读取数据
function mapStateToProps(state) {
let { getRestSortList,getRestList,getRestScrollTop } = state.restReducer;
return {
restReducer:{
category: {
type:getRestSortList.type,
data:getRestSortList.data,
isFetching: getRestSortList.isFetching
},restsList: {
type:getRestList.type,
data:getRestList.data,
isFetching: getRestList.isFetching,}
},scrollTop:getRestScrollTop.scrollTop,sortId : getRestScrollTop.sortId,areaId : getRestScrollTop.areaId
}
}
//通过react-redux提供的connect方法将我们需要的state中的数据和actions中的方法绑定到props上
//第一个参数,必须是function,作用是绑定state的指定值到props上面。
//第二个参数,可以是function,也可以是对象,作用是绑定action创建函数到props上。
//返回值,是绑定后的组件
export default connect(mapStateToProps)(ChiAnYi);
action
action也是action目录中的一个文件,只不过里面全都是action的内容 ,可以看到用到了Promise模式的异步请求。
export const RESTLIST_REQUEST_TYPE = 'RESTLIST_REQUEST_TYPE'
//获取列表
export function request2(area_id,sort_id,page,cusPerPage,dispatch) {
const config = {
params: {
mt: 2,oper: 'findRestsList',page: page,sort:sort_id,area_id:area_id,cusPerPage: cusPerPage
}
}
// 获取接口数据
api.rest.get('/test/test-app',config)
.then(response => response.data )
.then(data => dispatch(complete(data)));
return {
type: RESTLIST_REQUEST_TYPE,isFetching: true,data:""
}
}
/** * 获取数据完成 */
function complete(data) {
return {
type: REST_REST_TYPE,isFetching: false,data: data
}
}
reducer
Redux提供了一个方法 combineReducers 专门来管理这些小Reducer。reduce中通过action中的type来判断是哪个action。在reduce中把action的数据assign到各自的state中
import { combineReducers } from 'redux';
import {RESTLIST_REQUEST_TYPE} from '../../action/restListAction'
import {FETCH_REST_REQUEST} from '../../action/wandaochi/restListAction'
import assign from 'lodash/assign';
// 返回饭店分类
function getRestSortList (
state = {
type:"",isFetching: false,data: {}
},action
) {
switch (action.type) {
// 请求
case FETCH_REST_REQUEST:
return assign({},state,{
type: action.type,isFetching: action.isFetching
});
break;
// 请求成功
case REST_REQUEST_TYPE:
return assign({},isFetching: action.isFetching,data: action.data
});
break;
default :
return state;
}
}
//。。。。其他reduce
const restSortListReducer = combineReducers({
getRestSortList,getRestScrollTop
});
export default restSortListReducer;