用react+redux编写一个页面小demo
初步目录结构
整体目录结构
【用react+redux编写一个页面小demo】
文章图片
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(,
document.getElementById('hello')
);
HelloPage.jsx
是视图文件,通过react-redux
中的Provider
将store
绑定到视图中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 functions
export 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中使用thunkMiddleware
export 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);
});
}
}
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;
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);
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) => ({i} {l.name}
{l.age} delete ));
return (
{loaded ? (加载完成) : (正在加载数据...)}
#
name
age
action
{personTbody}
show me the current count : {count || 0}
);
},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);
详细的页面,在页面中默认会带有从
store
中返回的状态,会以props
的形式传递到页面中,默认会带有一个dispatch
函数,用于发起action
,因此这个action
可以绑定页面的一些业务逻辑操作,比如:“新增”、“删除”、“修改”……推荐阅读
- Docker应用:容器间通信与Mariadb数据库主从复制
- JS中的各种宽高度定义及其应用
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- 涉毒患者(新诗)
- 参保人员因患病来不及到指定的医疗机构就医,能否报销医疗费用()
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。