【问题标题】:React Redux-dynamically creating Redux FormsReact Redux - 动态创建 Redux Forms
【发布时间】:2017-11-21 14:22:10
【问题描述】:

我正在构建一个允许用户邀请他们的朋友的组件。

该组件的规范是,它将有几个用于他们朋友的电子邮件和公司的输入表单,一个可以添加更多输入表单的按钮,以及一个可以远程提交所有表单的按钮。提交表单时,每个表单中都会出现一个微调器,直到收到来自服务器的响应,此时,如果提交成功,表单会消失,如果有错误,则会显示错误。

我遇到了以下问题:为了使用 Redux Form 远程提交表单,您需要将其名称传递给提交组件。我想以编程方式创建表单。名称将是自动递增的整数,由表单管理组件创建,并作为道具传递给子表单。但是,当我尝试导出表单并将名称引用为 this.props.name 时,出现错误:'Uncaught TypeError: Cannot read property 'props' of undefined'-“this”未定义。

问题:

  1. 我解决此问题的方法是否有效,或者我应该在基本层面上做一些不同的事情?
  2. 如何解决这个问题?我认为这是一个范围错误?

我的组件:

管理组件(创建和删除表单、提交表单等):

import React, { Component } from 'react';
import { connect } from 'react-redux'
import { submit } from 'redux-form'
import * as actions from '../../actions';
import InviteForm from './inviteForm';

class InvitationFormManager extends Component {

  const buildForms = (length) =>{
    for (let i = 0; i< length; i++)
        {
          this.setState({forms:[...this.state.forms, <InviteForm key={i} name={i}>]};
        }
  }

  const addForm = () =>{
    this.setState({forms:[...this.state.forms, <InviteForm key={(this.state.forms.length + 1)} name={(this.state.forms.length + 1)}>]});
  }

  const formSubmit = (form) =>
  {
    dispatch(submit(form.name))
    .then(this.setState({
      forms: this.state.forms.filter(f => f.name !== form.name)
    }))
  }
  const submitForms = (){
    for(let form of this.state.forms){formSubmit(form)}
  }

  constructor(props) {
      super(props);
      this.state = {forms:[]};
  }

  componentWillMount(){
    buildForms(3)
  }

  render() {
    return (<div>
              <h5 className="display-6 text-center">Invite your team</h5>
              {this.state.forms}
              <br />
              <button
                type="button"
                className="btn btn-primary"
                onClick={submitForms}
              >
                Invite
              </button>
              <button
                type="button"
                className="btn btn-primary"
                onClick={addForm}
              >
                +
              </button>
          </div>
      );
    }
}


export default connect(actions)(InvitationFormManager)

表单组件:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import * as actions from '../../actions';
import { Link } from 'react-router';

const renderField = ({
    input,
    label,
    type,
    meta: { touched, error, warning }
}) => (
    <fieldset className="form-group">
        <label htmlFor={input.name}>{label}</label>
        <input className="form-control" {...input} type={type} />
        {touched && error && <span className="text-danger">{error}</span>}
    </fieldset>
);

class InviteForm extends Component {
    constructor(props) {
        super(props);
        this.name = this.name.bind(this);
    }

    handleFormSubmit(props) {
        this.props.sendInvitation(props);
    }

    render() {
        if (this.props.submitting) {
            return (
                <div className="dashboard loading">
                    <Spinner name="chasing-dots" />
                </div>
            );
        }
        const { formName, handleSubmit } = this.props;
        return (
            <div className="form-container text-center">
                <form
                    className="form-inline"
                    onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
                    <div className="form-group">
                        <Field
                            name="email"
                            component={renderField}
                            type="email"
                            label="Email"
                        />
                        <Field
                            name="company"
                            component={renderField}
                            type="text"
                            label="Company"
                        />
                    </div>
                </form>
                <div>
                    {this.props.errorMessage &&
                        this.props.errorMessage.invited && (
                            <div className="error-container">
                                Oops! {this.props.errorMessage.invited}
                            </div>
                        )}
                </div>
            </div>
        );
    }
}
function validate(values) {
    let errors = {};

    if (values.password !== values.password_confirmation) {
        errors.password = "Password and password confirmation don't match!";
    }

    return errors;
}
function mapStateToProps(state) {
    return {
        errorMessage: state.invite.error,
        submitting: state.invite.submitting
    };
}

InviteForm = reduxForm({
    form: this.props.name,
    validate
})(InviteForm);
export default connect(mapStateToProps, actions)(InviteForm);

【问题讨论】:

    标签: javascript reactjs redux-form react-redux-form


    【解决方案1】:

    答案是,RTFM。 Redux Form 作为 FieldArrays 具有此功能。

    Redux Form 7.0.4 的示例在这里:https://redux-form.com/7.0.4/examples/fieldarrays/

    如果他们稍后移动它,这里是:

    FieldArraysForm.js

    import React from 'react'
    import { Field, FieldArray, reduxForm } from 'redux-form'
    import validate from './validate'
    
    const renderField = ({ input, label, type, meta: { touched, error } }) =>
      <div>
        <label>
          {label}
        </label>
        <div>
          <input {...input} type={type} placeholder={label} />
          {touched &&
            error &&
            <span>
              {error}
            </span>}
        </div>
      </div>
    
    const renderHobbies = ({ fields, meta: { error } }) =>
      <ul>
        <li>
          <button type="button" onClick={() => fields.push()}>
            Add Hobby
          </button>
        </li>
        {fields.map((hobby, index) =>
          <li key={index}>
            <button
              type="button"
              title="Remove Hobby"
              onClick={() => fields.remove(index)}
            />
            <Field
              name={hobby}
              type="text"
              component={renderField}
              label={`Hobby #${index + 1}`}
            />
          </li>
        )}
        {error &&
          <li className="error">
            {error}
          </li>}
      </ul>
    
    const renderMembers = ({ fields, meta: { error, submitFailed } }) =>
      <ul>
        <li>
          <button type="button" onClick={() => fields.push({})}>
            Add Member
          </button>
          {submitFailed &&
            error &&
            <span>
              {error}
            </span>}
        </li>
        {fields.map((member, index) =>
          <li key={index}>
            <button
              type="button"
              title="Remove Member"
              onClick={() => fields.remove(index)}
            />
            <h4>
              Member #{index + 1}
            </h4>
            <Field
              name={`${member}.firstName`}
              type="text"
              component={renderField}
              label="First Name"
            />
            <Field
              name={`${member}.lastName`}
              type="text"
              component={renderField}
              label="Last Name"
            />
            <FieldArray name={`${member}.hobbies`} component={renderHobbies} />
          </li>
        )}
      </ul>
    
    const FieldArraysForm = props => {
      const { handleSubmit, pristine, reset, submitting } = props
      return (
        <form onSubmit={handleSubmit}>
          <Field
            name="clubName"
            type="text"
            component={renderField}
            label="Club Name"
          />
          <FieldArray name="members" component={renderMembers} />
          <div>
            <button type="submit" disabled={submitting}>
              Submit
            </button>
            <button type="button" disabled={pristine || submitting} onClick={reset}>
              Clear Values
            </button>
          </div>
        </form>
      )
    }
    
    export default reduxForm({
      form: 'fieldArrays', // a unique identifier for this form
      validate
    })(FieldArraysForm)
    

    验证.js

    const validate = values => {
      const errors = {}
      if (!values.clubName) {
        errors.clubName = 'Required'
      }
      if (!values.members || !values.members.length) {
        errors.members = { _error: 'At least one member must be entered' }
      } else {
        const membersArrayErrors = []
        values.members.forEach((member, memberIndex) => {
          const memberErrors = {}
          if (!member || !member.firstName) {
            memberErrors.firstName = 'Required'
            membersArrayErrors[memberIndex] = memberErrors
          }
          if (!member || !member.lastName) {
            memberErrors.lastName = 'Required'
            membersArrayErrors[memberIndex] = memberErrors
          }
          if (member && member.hobbies && member.hobbies.length) {
            const hobbyArrayErrors = []
            member.hobbies.forEach((hobby, hobbyIndex) => {
              if (!hobby || !hobby.length) {
                hobbyArrayErrors[hobbyIndex] = 'Required'
              }
            })
            if (hobbyArrayErrors.length) {
              memberErrors.hobbies = hobbyArrayErrors
              membersArrayErrors[memberIndex] = memberErrors
            }
            if (member.hobbies.length > 5) {
              if (!memberErrors.hobbies) {
                memberErrors.hobbies = []
              }
              memberErrors.hobbies._error = 'No more than five hobbies allowed'
              membersArrayErrors[memberIndex] = memberErrors
            }
          }
        })
        if (membersArrayErrors.length) {
          errors.members = membersArrayErrors
        }
      }
      return errors
    }
    
    export default validate
    

    【讨论】:

      猜你喜欢
      • 2017-07-18
      • 2016-03-09
      • 2019-03-09
      • 2017-08-02
      • 1970-01-01
      • 1970-01-01
      • 2019-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多