2017-11-21 12 views
0

사용자가 친구를 초대 할 수있게하는 구성 요소를 구축 중입니다.Redux 동적으로 Redux 양식 생성하기

구성 요소의 사양은 친구들의 전자 메일 및 회사에 대한 여러 입력 양식, 더 많은 입력 양식을 추가하는 단추 및 모든 양식을 원격으로 제출하는 단추를 갖게된다는 것입니다. 양식이 제출되면 서버에서 응답을받을 때까지 각 양식에 회 전자가 나타납니다. 제출이 성공하면 양식이 사라지고 오류가있는 경우 오류가 표시됩니다.

다음과 같이 처리됩니다 : Redux Form을 사용하여 양식을 원격으로 제출하려면 제출 구성 요소에 이름을 전달해야합니다. 프로그래밍 방식으로 양식을 만들고 싶습니다. 이름은 폼 관리 구성 요소에 의해 생성되고 자식 폼에 전달되는 자동 증가 정수가 될 것입니다. 그러나 this.props.name 같은 이름을 참조하는 양식을 내보낼 때 오류가 발생합니다. '잡히지 TypeError : 프로퍼티'정의되지 않은 '소품'읽을 수 없습니다 - "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); 

답변

1

대답은 , RTFM. Redux Form은이 기능을 FieldArrays로 가지고 있습니다.

돌아 오는 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) 

validate.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