使用react+redux搭建one单页应用

什么是React?

React

当今的前端正处于技术爆发期,这个阶段涌现很多优秀的编程思想以及框架,本文所介绍的react就是 前端的一种框架,它使用单向数据绑定以及jsx语法糖,通过它提供的特性,可以构建去区别于以前传统 型的网页。

什么是Redux?

redux

单页模式区别于传统模式开发,比如用户的登录状态、数据列表的缓存,传统类型的MVC设计模式中,后端语言(Java、PHP......)中,浏览器发起url请求,后端根据请求的路径和参数,后端对数据进行处理(从数据库中拿出数据、请求第三方接口等......),然后进行页面数据填充后返回完整的HTML数据,浏览器拿到这些html元素后进行页面渲染。

单页应用模式的区别在于请求进行接口化,开发过Android或者iOS的应该知道,客户端处理数据状态,操作UI控件,与后端进行网络通信获取数据通信。单页应用的开发就是基于这种模式,那么处理数据状态的任务就落到前端的头上来了,react提供视图渲染的优化,但是数据的状态管理就成了一个问题,比如用户的数据,交由那个组件去控制,怎么进行交互,这就成了一个问题。Facebook提出了Flux设计模型来解决这个问题,用store来存放数据源,通过action、reducer来操作数据,来保证数据的单一性。

但是Facebook只是提出了这一种设计思想,没有开发相应的框架,于是就诞生了很多第三方实现,Redux就是其中一种,它不是完全采用Flux规范模式,它提出了自己的设计思想,Redux也就成了和React搭配的优秀的状态工具。

项目生成

代码生成工具使用Yeoman,Yeoman是一个代码generators工具,它提供很多第三方generators,通过它,我们可以很方便的构建一个初始化项目,点击访问Yeoman

项目使用react+redux构建,所以这里选择generator-redux-stack来作为生成模板。终端下使用如下命令:

#安装yeoman
npm install yo -g 

#安装generators
npm install -g generator-redux-stack

#创建目录并进入
mkdir [xxx] && cd [xxx]

#使用yo创建项目框架
yo redux-stack

执行完成后会看到下图 yo

填写相应的项目描述信息,Yeoman会自动创建文件,并且安装依赖

npm

如果网络较慢可以Ctrl+C停止安装,使用cnpm国内镜像安装(#滑稽)。

cnpm

稍等一会出现如下界面就说明完成了

finash

在终端输入

npm start

浏览器端打开http://localhost:3000可以看到生成器提供的模板

web

好了,接下来就可以开始编码了。:)

目录介绍

file

目录结构由redux-stack控制

| 目录名 | 描述 | | ----- | :--- | |build|项目主html文件存放位置| |dist|项目编译目录位置| |node_modules|npm包存放位置| |server|项目运行时服务器环境| |src|项目源码目录,代码主要存放位置| | ----actions|redux action存放目录| | ----components|react组件存放目录| | ----config|react-router主要配置文件| | ----container|react页面(组件拼贴)存放位置| | ----reducers|redux reducer存放位置| | ----store|redux store定义存放位置| | ----style|样式文件存放位置| | ----utils|开发调试工具配置| |test|测试脚本存放目录|

编写代码

编写jsx页面

container目录新创建一个Home.js文件

// src/containers/Home.js
import React, { Component } from 'react';

export default class Home extends Component {
  render () {
    return (
      <div>
        这是主页
      </div>
    )
  }
}

这里创建了一个组件,组件渲染了一个div标签,里面是一行文字。render使用了jsx的语法糖。

编写路由

修改config目录下面的routes.js文件,需要引入Home组件,并且将其挂载到根节点。

// src/config/routes.js
import Home from '../containers/Home.js';

export default (
  <Route path="/" component={Home} />
);

刷新路由器可以看到页面的更改

编写action

src/actioins目录下面创建one.js文件,这里面将会定义数据操作类型与一些actions方法。

// actions/one.js
import 'whatwg-fetch';
export const UPDATE_ONE = 'update_one';

export function update(_data) {
  return {
    type: UPDATE_ONE,
    data: _data
  };
}

export function getone() {
  return dispatch => {
    fetch('http://v3.wufazhuce.com:8000/api/hp/bymonth/2016-09')
      .then((response) => {
        console.log(response)
      })
  };
}

这里我们需要安装fetch来进行异步网络请求,当然你也可以使用其他网络请求工具。通过以下命令安装fetch

npm install whatwg-fetch --save

接口使用WeexOne项目里面的接口

编写reducer

redux-stack这个生成器自动帮我们做好了reducer到store的绑定,所以我们只需要将注意力放在reducer中就可以了。

src/reducers目录下新建one.js文件,这里我们将放置一些常用的数据操作。

// reducers/one.js
import { createReducer } from 'redux-create-reducer';
import { UPDATE_ONE } from '../actions/one';

const initialState = {};

export default createReducer(initialState, {
  [UPDATE_ONE](state, data) {
    return data.data;
  }
});

并在reducers/index.js文件中注册store

// reducersindex.js
......
import one from './one';

const rootReducer = combineReducers({
  ......
  one,
  ......
});

export default rootReducer;

绑定store和actions到组件

这里我们需要修改开始创建的Home.js组件。

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as OneActions from '../actions/one';

class Home extends Component {
  componentWillMount() {
    this.props.getone() //发起action操作
  }
  render() {
    return (
      <div>
        这是主页
      </div>
    )
  }
}

/* 映射store中的state到组件中 */
function mapStateToProps(state) {
  return {
    one: state.one
  };
}

/* 映射actions到组件中,并且注入dispatch方法 */
function mapDispatchToProps(dispatch) {
  return bindActionCreators(OneActions, dispatch);
}

/* 修改组件导出方式,导出调用connect方法生成后的新组件*/
export default connect(mapStateToProps, mapDispatchToProps)(Home);

这里注入的state与actions都可以通过this.props访问到。这时打开浏览器可以看到我们在one action中的getone方法打印出的异步请求数据 response

将异步数据写入到state

修改actions当中的one.js,在拿到数据后dispatch到reducer处理

// actions/one.js
import 'whatwg-fetch';
export const UPDATE_ONE = 'update_one';

export function update(_data) {
  return {
    type: UPDATE_ONE,
    data: _data
  };
}

export function getone() {
  return dispatch => {
    fetch('http://v3.wufazhuce.com:8000/api/hp/bymonth/2016-09').then((response) => {
        console.log(response)
        return response.json()
      }).then((data) => {
        /** 返回的json格式为
        {
          res: 0,
          data: [...]
        }
        */
        dispatch(update(data.data[0]))
      })
  };
}

由于fetch库提供Promise的支持,所以可以使用then结构。

在redux开发工具中我们可以看到如下显示

reduxtool

在末尾处可以看到state中的one已经有数据了,接下来我们将数据绑定到界面组件。

绑定store中的state数据到react组件

回到还是创建的Home.js组件中,我们将需要的数据绑定到界面中

......
  render() {
    const { one } = this.props
    return (
      <div>
        <h2>{one.hp_content}</h2>
        <hr/>
        <p>{one.hp_author}</p>
        <img src={one.hp_img_url}></img>
      </div>
    )
  }
......

这是浏览器里面的页面已经有数据了

perview

经过一些简单的css样式调整得到的效果如下

one

结语

这篇文章讲述了react搭配redux的基础用法,关于react-router的部分本文没有详细讲解,但是react-router的难度也不大,上手也很快。如果需要使用webpack ensure按需加载,需要将组建导出格式换成CommonJS规范导出

module.exports = React.createClass({
  render() {
    <div>示例页面</div>
  }
})

详细可以参考react-router示例程序