背景交代
举个例子。有个内容编辑的页面,如下图。它由不同的子组件(输入框组件A、图片上传组件B、富文本编辑组件C等)组成。不同的子组件负责页面中的不同的数据。点击【保存草稿】、【预览提交】按钮,将所有数据传送到后端。
原来对数据的处理是:A、B、C等子组件在每次value发生变化时,使用this.props.callback(xxx, xxx, xxx)的形式,将自己所包含的数据传出。
现改为使用redux维护数据:
/****** 我的习惯是先看怎么用,再看为什么这么用。所以接下来我们先看下怎么用。 ******/
怎么用
1.安装依赖
npm install --save redux
npm install --save react-redux
2.构建
最常用的3种项目结构:①按照类型;②按照功能;③Ducks。具体解释可参见React+Redux项目结构最佳实践。
Ducks是一种新的Redux项目结构的提倡。它提倡将关联的reducer、action types和action写在同一个文件里。本文采用这种结构。
第一步 在src中新建文件夹redux,然后在redux文件中新建一个文件configureStore.js。此时的文件结构如下:
第二步 在configureStore.js文件中添加下面的代码:
import { createStore, applyMiddleware, combineReducers } from 'redux';
import contentCreate from './modules/content_create';
const createStoreWithMiddleware = applyMiddleware()(createStore);
const reducer = combineReducers({contentCreate});
const configureStore = (initialState) => createStoreWithMiddleware(reducer, initialState);
export default configureStore;
第三步 在redux文件夹中新建文件夹modules,然后在modules中新建一个文件,并以容器组件的名字来命名。此时的文件结构如下:
第四步 在新创建的文件(这里是content_create.js)中添加下面的代码:
const UPDATE_CREATE_DATA = Symbol('UPDATE_CREATE_DATA');
export function updateCreateData (index) {
return {
type: UPDATE_CREATE_DATA,
index,
};
}
const initialState = {
draftData: {}, // 草稿数据
finalData: {}, // 最终的数据
};
export default function reducer (state = initialState, action) {
switch (action.type){
case UPDATE_CREATE_DATA:
return Object.assign(
{},
state,
{
draftData: {...state.draftData},
finalData: {...state.finalData},
}
);
default:
return state;
}
}
3.与app建立联系
第一种方案:改造原先的容器组件(这里假设为是content_create)。
第一步 新增下列import语句:
import { connect } from 'react-redux';
import {
updateCreateData,
} from '../redux/modules/content_create';
第二步 新增下列函数:
function mapStateToProps (state) {
return {
draftData: state.draftData, // 草稿数据
finalData: state.finalData, // 最终的数据
};
}
function mapDispatchToProps (dispatch) {
return {
updateCreateData: (value) => dispatch(updateCreateData(value)),
};
}
第三步 将原先的export default XXX语句改成如下:
export default connect (
mapStateToProps,
mapDispatchToProps
)(XXX);
最终应该是这样的:
// 原先的import语句
import { connect } from 'react-redux';
import {
updateCreateData,
} from '../redux/modules/content_create';
function mapStateToProps (state) {
return {
draftData: state.draftData, // 草稿数据
finalData: state.finalData, // 最终的数据
};
}
function mapDispatchToProps (dispatch) {
return {
updateCreateData: (value) => dispatch(updateCreateData(value)),
};
}
class XXX extends Component {
// ...
}
export default connect (
mapStateToProps,
mapDispatchToProps
)(XXX);
第二种方案:原先的容器组件不变,新增 content_create_containers.js文件,并将项目中对原容器组件的引用改为对新增的这个 content_create_containers.js的引用。代码类似。
第一步 在src下新建文件夹containers,并在改文件夹下创建一个文件,以`${容器组件名}_containers`命名。
第二步 在新创建的文件(这里是content_create_containers.js)中添加下面代码:
import { connect } from 'react-redux';
import contentCreate from '../react/pages/content_create';
import {
updateCreateData,
} from '../redux/modules/content_create.js';
function mapStateToProps (state) {
return {
draftData: state.draftData, // 草稿数据
finalData: state.finalData, // 最终的数据
};
}
function mapDispatchToProps (dispatch) {
return {
updateCreateData: (value) => dispatch(updateCreateData(value)),
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(contentCreate);
第三步 将项目中对原容器组件的引用改为对新增的这个 content_create_containers.js的引用。如在router文件中有对content_create的引用,那么将import contentCreate from './XXX/content_create' 改成import contentCreate from './YYY/content_create_containers.js'。
4.改造app.js
第一步 新增下列import语句。
import { Provider } from 'react-redux';
import contentCreateContainer from './containers/content_create_container';
import configureStore from './redux/configureStore';
第二步 声明一个常量store,并把它传给Provider组件。
const store = configureStore();
<Provider store={store}>
{/* 原先的组件 */}
</Provider>
为什么
到这里,已经可以用起来了。心里有点沾沾自喜。但是我们再花几分钟的时间看一下为什么要这么做吧。因为我们是好奇宝宝呀~(同事说用波浪号的都是女生~_~)
未完待续......