用react+redux编写一个页面小demo

来源:互联网 发布:转基因食品 知乎 编辑:程序博客网 时间:2024/06/05 22:06

用react+redux编写一个页面小demo

原创 2016年07月11日 14:36:10

初步目录结构

整体目录结构

这里写图片描述

src目录结构

这里写图片描述

entry 存放页面的入口文件

src 页面的源文件

static 页面源文件打包后生成的文件

webpack webpack打包文件

package.json package.json文件

.babelrc 支持es6语法

其中 src 中子目录结构如下:

components 页面组件

constants 页面需要用到的一些常量

helpers 工具方法

mock 模拟json数据

redux redux数据控制目录

views 页面视图文件,主要视图全在这个文件

react配合redux编写页面流程

entry/hello.js

import React from 'react';import { render } from 'react-dom';import HelloPage from '../src/views/HelloPage';import helloStore from '../src/redux/stores/helloStore';import { Provider } from 'react-redux';render(    <Provider store={helloStore}>        <HelloPage />    </Provider>,    document.getElementById('hello'));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

HelloPage.jsx是视图文件,通过react-redux中的Providerstore绑定到视图中

src/redux/actions/helloAction.js

import fetch from 'isomorphic-fetch';// 纯事件定义export const ADD_COUNT = 'ADD_COUNT';export const ADD_PERSON = 'ADD_PERSON';export const DELETE_PERSON = 'DELETE_PERSON';// async// 异步的请求定义export const FETCH_START = 'FETCH_START';export const FETCH_SUCCESS = 'FETCH_SUCCESS';export const FETCH_FAUILE = 'FETCH_FAUILE';// pure functionsexport function addCount() {    return {        type : ADD_COUNT    }}export function addPerson(person) {    return {        type : ADD_PERSON,        person    }}export function deletePerson(idx) {    return {        type : DELETE_PERSON,        idx    }}export function refreshStart() {    return {        type : FETCH_START    }}export function refreshSuccess(list) {    return {        type : FETCH_SUCCESS,        list    }} export function refreshFauile() {    return {        type : FETCH_FAUILE    }}// 定义的非纯函数,提供异步请求支持// 需要在sotre中使用thunkMiddlewareexport function refresh() {    return dispatch => {        dispatch(refreshStart());        return fetch(`src/mock/fetch-data-mock.json`)            .then(response => response.json())            .then(json => {                setTimeout(() => {                    dispatch(refreshSuccess(json && json.data.list));                }, 3000);            });    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

action中主要定义事件类型,基本上都是一些常量。另外如果要进行一些非常量返回,比如异步请求,则需要输出一个函数,这个函数通常带有dispatch这个对象,用于对action的重新包装,其实类似于后台语言中的“拦截器”,返回函数之后,需要在store中配置thunkMiddleware

src/redux/reducers/helloReducers.js

import { combineReducers } from 'redux';import { ADD_COUNT, ADD_PERSON, DELETE_PERSON, FETCH_START, FETCH_SUCCESS, FETCH_FAUILE } from '../actions/helloActions';// store中可以定义页面中的初始状态const initialState = {    count : 0,      // count = 0    loaded : false, // 异步请求是否加载    personList : [  // 人员列表        {"name" : "lily", "age" : 21}    ]};// count的初始状态以及处理之后返回的state值function count(state = initialState.count, action) {    switch (action.type) {        case ADD_COUNT :             return state + 1;        default :             return state;    }}function personList(state = initialState, action) {    switch (action.type) {        case ADD_PERSON :             return Object.assign({}, ...state, {                personList : [...state.personList, action.person]            });        case DELETE_PERSON :            return Object.assign({}, ...state, {                personList : state.personList.filter((s, i) => {                    return action.idx !== i;                })            });        case FETCH_START :        case FETCH_SUCCESS :         case FETCH_FAUILE :             return fetchDataFromServer(state, action);        default :             return state;    }}function fetchDataFromServer(state, action) {    if (action.type === FETCH_SUCCESS) {        console.log(action);        return Object.assign({}, ...state, {            personList : [...state.personList, ...action.list],            loaded : true        });    }    return state;}const helloReducers = combineReducers({    count,    personList});export default helloReducers;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

reducer中是对action发起的数据进行处理,这其中可能action只是发出了一个纯指令,带参数或者不带参数根据业务的需求来定,总一个准则就是,初始的state经过处理之后会返回新的state。即:( state, action ) => newState。同时另外注意一点的是,初始的state值是不会变得,需要操作则会另外创建一个新的state,来保证某些场景的性能问题(因为状态的改变会导致页面重新渲染,如果返回的state引用相同,则不会存在如此问题)。可以使用Immutable.js来保证state的纯洁性。

src/redux/stores/helloStore.js

import { createStore, applyMiddleware } from 'redux';import helloReducers from '../reducers/helloReducers';import logger from '../middlewares/loggerMiddleWare';import thunkMiddleware from 'redux-thunk';// middleware可以自己定义,例如下面的logger// 写一个自定义的middleware遵循下面的格式:// const logger = store => next => action => {//  // what you do before action, //      // example: logger. console.log("dispatching", action);//  let result = next(action);//      // what you can do after action    //  //console.log('next state', store.getState());//  return result;//}let createStoreWithMiddleware = applyMiddleware(/*logger, */thunkMiddleware)(createStore);export default createStoreWithMiddleware(helloReducers);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

store中主要绑定从reducer返回的状态

src/views/HelloPage.jsx

import React from 'react';import { connect } from 'react-redux';import { addCount, addPerson, deletePerson, refresh } from '../redux/actions/helloActions';import HelloWorld from '../components/hello/HelloWorld';import Button from 'react-bootstrap-myui/lib/Button';import Table from 'react-bootstrap-myui/lib/Table';const HelloPage = React.createClass({    render () {        let { count, list, loaded } = this.props;        let personTbody = list.map((l, i) => (<tr key={"tr"+i}><td>{i}</td><td>{l.name}</td>            <td>{l.age}</td><td><a href="javascript:;" onClick={this.deletePerson.bind(this, i)}>delete</a></td></tr>));        return (            <div id="reactPage">                <HelloWorld />                <Button onClick={this.addperson}>add person</Button>                <Button onClick={this.refresh}>refresh</Button>                {loaded ? (<span>加载完成</span>) : (<span>正在加载数据...</span>)}                <Table striped hover>                    <thead>                        <tr>                            <th>#</th>                            <th>name</th>                            <th>age</th>                            <th>action</th>                        </tr>                    </thead>                    <tbody>                        {personTbody}                    </tbody>                </Table>                <span>show me the current count : {count || 0}</span>                <div><button onClick={this.addCount}>Add</button></div>            </div>        );    },    addCount() {        let { dispatch, count } = this.props;        dispatch(addCount());    },    addperson() {        let { dispatch } = this.props;        dispatch(addPerson({"name" : "tome", age : 25}));    },    deletePerson(index) {        let { dispatch } = this.props;        dispatch(deletePerson(index));    },     refresh() {        let { dispatch } = this.props;        dispatch(refresh());    }});function select(state) {    return {        count : state.count,        list : state.personList.personList,        loaded : state.personList.loaded    }}export default connect(select)(HelloPage);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

详细的页面,在页面中默认会带有从store中返回的状态,会以props的形式传递到页面中,默认会带有一个dispatch函数,用于发起action,因此这个action可以绑定页面的一些业务逻辑操作,比如:“新增”、“删除”、“修改”……

原创粉丝点击