Yutt's Blog

使用Redux Form快速构建表单的redux数据流

2018/01/09 Share

无论再那种应用中,表单都是一种常见的提交数据的方式,在 reac 或 react native 中也不例外。但是,当通过 redux 来管理应用的数据之后,该如何来构建表单的数据流呢?或者更简单的说,对于使用 redux 处理表单的数据,需要哪些 Action 呢?经过简单的思考,可以想到这些 Action:

  • 表单组件挂载时,初始化(或者说创建)表单数据;
  • 用户更改表单数据时,修改相应的 state 的值;
  • 表单数据同步验证;
    …..
  • 离开表单界面时,销毁数据

Rdux Form 的作用正是通过 React 高阶组件的方式,自动创建这些数据流。由于高阶组件的本质是纯函数,不会受到原组件的结构影响,所以即使 React Native 中没有 form 相关的概念,依然适用。由于官网已经给出了 react 的相关例子,因此我在记录时,改用 React Native,同时在例子中配合使用了 immutable。

将 form 加入到 reducer 中

redux/reducers/index.js

1
2
3
4
5
6
7
import { combineReducers } from 'redux-immutable';
import { reducer as form } from 'redux-form/immutable';

const appReducers = combineReducers({
// ...你的其他reducers
form
});

使用 Form 高阶组件包裹原组件

containers/SendMessage.js

1
const SendMessageForm = reduxForm({ form: 'message' })(SendMessageView);

高阶组键一般采用柯里化的方式传递参数,当前步骤需要两个参数,这里的 SendMessageView 为表单界面的 UI 组件

使用 Field 组建包裹表单控件(如 Input,Select…)

containers/SendMessage.js

1
2
3
4
5
<Field
name="theme"
component={CommonInput}
placeholder="请输入主题"
/>

将CommonInput作为component属性的参数传入,如果CommonInput也需要某写属性,可直接作为Field的属性传入。同时,我也打印了日志文件的输出(通过redux-saga创建的一个简单日志),可以“监听”redux的一举一动。
日志: action {type: “@@redux-form/REGISTER_FIELD”, meta: {…}, payload: {…}}

改造表单控件

components/CommonInput.js
改造前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from 'react';
import { Input } from 'teaset';

// 输入框
const CommonInput = ({
placeholder = null,
value = null,
onChangeText = null,
width = 150,
height = 34,
...rest
}) => (
<Input
style={{ width, height }}
placeholder={placeholder}
value={value}
onChangeText={onChangeText}
{...rest}
/>
);

改造后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const CommonInput = ({
placeholder = null,
width = 150,
height = 34,
input,
...rest
}) => (
<Input
style={{ width, height }}
placeholder={placeholder}
value={input && input.value ? input.value : null}
onChangeText={inputText => input.onChange(inputText)}
{...rest}
/>
);

通过redux-form自动传入的属性input,我们可以获取和修改相应的state。
日志:
action {type: “@@redux-form/CHANGE”, meta: {…}, payload: “S”}

action {type: “@@redux-form/CHANGE”, meta: {…}, payload: “Sd”}

action {type: “@@redux-form/CHANGE”, meta: {…}, payload: “Sdf”}

添加表单同步验证

containers/SendMessage.js

1
2
3
4
5
6
7
8
9
10
11
const validate = values => {
const errors = {};
if (!values.get('theme')) {
errors.theme = 'Required';
}
return errors;
};
const SendMessageForm = reduxForm({
form: 'message',
validate
})(SendMessageView);

日志: action {type: “@@redux-form/UPDATE_SYNC_ERRORS”, meta: {…}, payload: {…}}

通过formValueSelect快速获取字段

containers/SendMessage.js

1
2
3
4
5
6
7
8
9
10
11
import { reduxForm, Field, formValueSelector } from 'redux-form/immutable';

const select = formValueSelector('message');
const mapStateToProps = state => ({
users:
state.getIn(['employees', 'data']) &&
state.getIn(['employees', 'data']).toJS(),
company: select(state, 'company'),
dept: select(state, 'dept'),
sendName: state.getIn(['auth', 'data', 'name'])
});

提交表单

提交表单时,会根据validate函数自动验证,如果失败,则不会触发处理提交的函数

containers/SendMessage.js

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
submit = values => {
const {
employee,
lx,
theme,
content,
zt,
action
} = values.toJS();
this.props.sendMessageFetch(
employee,
this.props.sendName,
lx,
theme,
content,
zt,
action
);
this.props.reset();
};

<Button
title="发送"
backgroundColor={AppColor.SUCCESS}
borderRadius={5}
containerViewStyle={CommonStyles.elementButton}
onPress={this.props.handleSubmit(this.submit)}
/>

这里与react中有些区别,需要handlesubmit属性去触发onSubmit事件,然后将处理提交的函数作为其参数。

清空表单

containers/SendMessage.js

1
this.props.reset();

改值

containers/SendMessage.js

1
this.props.change('fieldName', values);

CATALOG
  1. 1. 将 form 加入到 reducer 中
  2. 2. 使用 Form 高阶组件包裹原组件
  3. 3. 使用 Field 组建包裹表单控件(如 Input,Select…)
  4. 4. 改造表单控件
  5. 5. 添加表单同步验证
  6. 6. 通过formValueSelect快速获取字段
  7. 7. 提交表单
  8. 8. 清空表单
  9. 9. 改值