如何使用React处理复杂的表单

时间:2017-09-06 07:03:59

标签: reactjs redux

处理复杂表单(有或没有redux)的React方法是什么?我想移植一个具有嵌套数据模型的表单/文档的应用程序,并且很难找到一个示例。

简化数据模型:

var model = {
    name: {
        first: 'Firstname',
        last: 'Lastname'
    },
    age: 25,
    hobbies: [{
        name: 'fising',
        medals: [{
            name: 'Gold medal',
            year: 2000
        }]
    }, {
        name: 'sleeping',
        medals: [{
            name: 'Gold medal',
            year: 2000
        }, {
            name: 'Gold medal',
            year: 2014
        }]
    }],
    education: [{
        school: 'School 1',
        year: 2000
    }, {
        school: 'School 2',
        year: 2010
    }]
}

使用angularjs的示例 - http://jsfiddle.net/HB7LU/30964/

2 个答案:

答案 0 :(得分:3)

多表格处理程序

您可以创建自己的表单处理程序,创建一个组件,其中包含一个接收一些道具的输入...并检查它是否随onChange发生变化,该action creator会调用发送action的{​​{1}} }改变了state。您可以在state属性上创建一个包含表单名称和输入属性的属性。

以下是使用React-bootstrap和Next.js的示例:

输入组件

import React, {Component} from 'react'
import { FormGroup, ControlLabel, FormControl } from 'react-bootstrap';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

import { inputChange } from '../actions';

class Input extends Component {
  inputChange = (title, name, e) => {
    this.props.inputChange(title, name, e.target.value)
  };

  render() {
    return (
      <div>
        <FormGroup controlId="formBasicText">
          <ControlLabel>{this.props.controlLabel}</ControlLabel>
          <FormControl
            disabled={this.props.disabled}
            type={this.props.type || 'Text'}
            placeholder={this.props.controlLabel}
            onChange={(e) => this.inputChange(this.props.title, this.props.name, e)}
            value={this.props.val}
          />
        </FormGroup>
      </div>
    )
  }
}

const mapDispatchToProps = dispatch => {
  return {
    inputChange: bindActionCreators(inputChange, dispatch)
  }
}

export default connect(null,mapDispatchToProps)(输入);     export default connect(null,mapDispatchToProps)(输入); 您可以多次使用此组件,最重要的是传递propstitlenameplaceholdertitle将成为表单的名称,name将成为输入的名称。

行动创作者

export const inputChange = (title, name, val) => dispatch => {
  return dispatch ({ type: INPUT_VALUE, title, name, val})
};

每次输入有任何更改时,都会调用此操作。

Form Reducer

export default (state = {}, action ) => {
  switch (action.type) {
    case 'INPUT_VALUE': 
      return { ...state, 
        [action.title]: 
          { ...state[action.title],  
            [action.name]: action.val 
          }
      };
    default:
      return state;
  }
}

E.g

import { Col, Row } from 'react-bootstrap';

import Input from '../handlers/Input';

const UserForm = () => {
    return (
      <div>
        <Row>
          <Col lg={8} lgOffset={4}>
            <Input controlLabel="Name" title="user" name="name" />
          </Col>
          <Col lg={8} lgOffset={4}>
            <Input controlLabel="Last name" title="user" name="lastName" />
          </Col>
          <Col lg={8} lgOffset={4}>
            <Input controlLabel="Email" type="email" title="user" name="email" />
          </Col>
          <Col lg={8} lgOffset={4}>
            <Input controlLabel="Password" type="password" title="user" name="password" />
          </Col>
        </Row>
      </div>
    )
}

export default UserForm;

输出

{
  "formReducer": {
    "user": {
      "name": "Jhon",
      "lastName": "Doe",
      "email": "jhondoe@test.com",
      "password": "Password123"
    }
  }
}

Demo

Full repo

答案 1 :(得分:1)

使用redux,有redux-form

如果没有redux,我会创建一个表单来处理字段更改,显示它们的值并警告可能的验证。

此外,创建另一个组件或容器,处理这些验证和更改,然后将它们传播回组件。

将此示例视为您可能需要和使用的大图。

const YourModelForm = ({ model, onChange }) => 
  <div>
    <input type="text" value={model.name.first} onChange={({ target }) => onChange('name.first', target.value)} />
    <input type="text" value={model.name.last} onChange={({ target }) => onChange('name.last', target.value)} />

    <input type="number" value={model.age} onChange={({ target }) => onChange('age', target.value)} />

    ...

    /*
     Here you can create custom components for each property that model has.
     Maybe a nice input text, dropdown, number fields and such.
     Remember to always keep them dumb for future reuses.
    */
  </div>

class YourModelContainer extends Component {
  constructor(props) {
    super(props)

    this.onModelChange = this.onModelChange.bind(this)
  }

  onModelChange(prop, newValue) {
    /*
    Update your model here. 
    - Dispatch a redux action, update your state as you wish
    */
  }

  render() {
    // Let's assume you've got your model as props. It also works from state as well
    const { model, onChange } = this.props

    return(
      <div>
        ...

        <YourModelForm model={model} onChange={onModelChange} />
      </div>
    )
  }
}