React&Redux:“由于未连接表单而取消了表单提交”

时间:2018-09-05 04:48:25

标签: javascript reactjs forms redux

我还是React和Redux的新手。因此,我知道redux-form的存在,但是我不打算在该项目中使用。因此,我正在做的是创建一个form而不使用redux-form。该form将从减速器中获取数据并将其传递给backend API

这是我的主要CreateListing.jsx页。

    // @flow
   import React from 'react';
   import { connect } from 'react-redux';
   import { Helmet } from 'react-helmet';
   import { SEOService } from '[services]';
   import CreateListingFormPage1 from './CreateListing/CreateListingFormPage1';
   import CreateListingFormPage2 from './CreateListing/CreateListingFormPage2';
   import CreateListingFormPage3 from './CreateListing/CreateListingFormPage3';
   import WhereAmI from './CreateListing/WhereAmI';
   import SuccessCreateListing from './CreateListing/SuccessCreateListing';

   type Props = {
    ...props...
  };

  class CreateListing extends React.Component<Props> {

getPageBySequence(pagenum) {
  // depending on whether User is logged in or not, show/hide the Login/Signup form which is Page3
  let sequence = [ CreateListingFormPage1, CreateListingFormPage2, CreateListingFormPage3 ];
  if (this.props.isLoggedIn) {
    sequence = [ CreateListingFormPage1, CreateListingFormPage2, CreateListingFormPage2 ];
  }
  return sequence[pagenum-1];
}

getSubmitCreateListing = (e) => {
  e.preventDefault();

  const propertyType = this.props.listingType;
  const propertyName = this.props.suggestedBuildings.selected;
  const propertyBuildingType = this.props.propertyBuildingType;
  const bedrooms = this.props.bed;
  const bathrooms = this.props.bath;
  const price = this.props.price;
  const builtUp = this.props.builtUp;
  const title = this.props.title;
  const tenure = this.props.tenure;
  const description = this.props.description;

  /* IN CASE USER NOT YET LOGGGED IN */
  if(this.props.isLoggedIn === false) {
    const email =  this.props.email;
    const password = this.props.password;

    this.props.cacheCreateListing({ email, password, propertyType, propertyName, propertyBuildingType, bedrooms, bathrooms, price, builtUp, title, tenure, description });
  }

  this.props.cacheCreateListing({ propertyType, propertyName, propertyBuildingType, bedrooms, bathrooms, price, builtUp, title, tenure, description });

  if(CreateListingFormPage1.landedTypes.includes(propertyBuildingType)) {
    this.props.geocodingRequired(true);
  }
  else {
    this.props.geocodingRequired(false);
  }
  this.props.onSubmitCreateListing();
}

onAuthenticateAndCreateListingButton() {
  if(this.props.isLoggedIn) {
    return(
      <div role="presentation">
        <div className={`column ${this.props.formCurrentPage === 1 ? '':'displayNone'}`}>
          <button type="button" className="Button button-next is-red" onClick={this.props.onNextClick}>
            NEXT
          </button>
        </div>
        <div className={`column ${this.props.formCurrentPage === 2 || this.props.formCurrentPage === 3 ? '':'displayNone'}`}>
          <button type="submit" className="Button button-create is-red" onClick={this.props.onLoadingCreateListing}>
            CREATE LISTING
          </button>
        </div>
      </div>
    )
  }
  return <div className={`column ${this.props.formCurrentPage < 3 ? '':'displayNone'}`}>
    <button type="button" className="Button button-next is-red" onClick={this.props.onNextClick}>
      NEXT
    </button>
  </div>
}

render() {
  if(this.props.isListingCreated){
    return <SuccessCreateListing />;
  }
  else if(this.props.isListingLoading){
    return <div className="create-listing-spinner" />
  }
  const CurrentPage = this.getPageBySequence(this.props.formCurrentPage);
  return (
    <div className={`CreateListing${this.props.isMobile ? '' : ' is-desktop'}`}>
      <Helmet>
        <title>{ SEOService.getMetaTitle('Create Property Listing') }</title>
        { SEOService.getCanonicalTag('/blogs') }
      </Helmet>
      <section className="CreateListing--Main">
        <div className="CreateListing--Container">
          <div className="CreateListing--WhereAmI">
            <WhereAmI page={this.props.formCurrentPage} />
          </div>
          <div className="CreateListing--Body">
            <form className="CreateListing--Form" onSubmit={ this.getSubmitCreateListing }>
              <CurrentPage />
              <div className='columns'>
                <div  className='column'/>
                {/* CHANGE THIS this.props.formCurrentPage < 3 later */}
                <div className={`column ${this.props.formCurrentPage > 1 && this.props.formCurrentPage < 4 ? '':'displayNone'}`}>
                  <button type="button" className="Button button-back" onClick={this.props.onPrevClick}>
                    BACK
                  </button>
                </div>
                { this.onAuthenticateAndCreateListingButton() }
                <div  className='column'/>
              </div>
            </form>
          </div>
        </div>
      </section>
    </div>
  );
}
  };

  const MapStateToProps = (state: State) => ({...});

  const MapDispatchToProps = (dispatch: Dispatch) => ({
   onLoadingCreateListing: () => dispatch({type: 'CREATE_LISTING_LOADING'}),
   onSubmitCreateListing: () => dispatch({type: 'CREATE_LISTING_SUBMIT_FORM'}),})

  export default connect(MapStateToProps,MapDispatchToProps)(CreateListing);

因此,我的<input type="text" />来自CreateListingFormPage1CreateListingFormPage2CreateListingFormPage3,并放在<CurrentPage />中。我的<form onSubmit={...}></form>在此CreateListing.jsx页中。我不知道是否可以这样做。

因此,当我单击“提交”时,我得到了Form submission canceled because the form is not connected的警告。

我在<input type="" />中的CreateListingFormPage1的示例是:

    // @flow
  import React from 'react';
  import { connect } from 'react-redux';
  import {Dropdown} from '[elements]';

  type Props = {...props...};

  class CreateListingFormPage2 extends React.Component<Props> {
    static get selectTenure() { return ["Select Tenure"].concat(this.tenureTypes) };
static get selectTitle() { return ["Select Title"].concat(this.titleTypes) };
static get selectBedroom() { return["Select Bedrooms no"].concat(this.bedroomNo) };
static get selectBathroom() { return["Select Bathrooms no"].concat(this.bathroomNo) };
static get tenureTypes(){
  return[
    "FREEHOLD",
    "LEASEHOLD",
    "OTHERS"
  ]};
  static get titleTypes(){
    return[
      "RESIDENTIAL",
      "COMMERCIAL",
      "INDUSTRIAL"
    ]};
  static get bedroomNo(){
    return[
      "1",
      "2",
      "3",
      "4",
      "5"
    ]};
  static get bathroomNo(){
    return[
      "1",
      "2",
      "3",
      "4",
      "5"
    ]};

get selectTenure() { return this.constructor.selectTenure; }
get selectTitle() { return this.constructor.selectTitle; }
get selectBedroom() { return this.constructor.selectBedroom; }
get selectBathroom() { return this.constructor.selectBathroom; }
get tenureTypes() { return this.constructor.tenureTypes; }
get titleTypes() { return this.constructor.titleTypes; }
get bedroomNo() { return this.constructor.bedroomNo; }
get bathroomNo() { return this.constructor.bathroomNo; }

hasInputError = (name) => {
  if (this.props.errors[name]) {
    return ' is-error';
  }
  return '';
}

render() {
  return (
    <div className={`Listing--Create${ this.props.isMobile ? '' : ' is-desktop' }`} id='form-second-page'>
      {/* <form className="Listing--form"> */}
        <div className="Listing--bedrooms-bathrooms">
          <div className="type-title">No. of Bedrooms</div>
          <Dropdown namespace="bedroom" selected={ this.selectBedroom[0] } options={ this.selectBedroom } onOptionSelect={ this.onBedroomDropdownSelect }/>

          <div className="type-title">Asking Price</div>
          <input className={`text-input price-input${ this.hasInputError('price')}`} type="text" onChange={ (e) => this.props.onPrice(e.currentTarget.value) } value={this.props.price} placeholder="RM"/>
        </div>

        <div className="Listing--price-built-up">
          <div className="type-title">No. of Bathrooms</div>
          <Dropdown namespace="bathroom" selected={ this.selectBathroom[0] } options={ this.selectBathroom } onOptionSelect={ this.onBathroomDropdownSelect }/>

          <div className="type-title">Built-up Size</div>
          <input className={`text-input built-up-input${ this.hasInputError('built_up_size')}`} type="text" onChange={ (e) => this.props.onBuiltUpSize(e.currentTarget.value) } value={this.props.builtUp} placeholder="sqft."/>
        </div>

        <div className="Listing--tenure">
          <div className="type-tenure">Select Tenure</div>
          <Dropdown namespace="tenure" selected={ this.selectTenure[0] } options={ this.selectTenure } onOptionSelect={ this.onTenureDropdownSelect }/>
        </div>

        <div className="Listing--title">
          <div className="type-title">Select Title</div>
          <Dropdown namespace="title" selected={ this.selectTitle[0] } options={ this.selectTitle } onOptionSelect={ this.onTitleDropdownSelect }/>
        </div>

        <div className="Listing--photos">
          <div className="type-title">Upload Photos</div>
          <button className={`text-input photos-input${ this.hasInputError('photos')}`}>Click to upload</button>
        </div>

        <div className="Listing--description">
          <div className="type-title">Describe your property</div>
          <textarea className={`text-input description-input${ this.hasInputError('description')}`} onChange={ (e) => this.props.onDescription(e.currentTarget.value) } value={this.props.description} placeholder="Describe your property"/>
        </div>
    </div>
  );
}
  };


  const MapStateToProps = (state: State) => ({
   ...
  });

  const MapDispatchToProps = (dispatch: Dispatch) => ({
   ...
  })

  export default connect(MapStateToProps, MapDispatchToProps)(CreateListingFormPage2);

基本上,我的redux商店没有任何问题。 input的所有值均已成功捕获。问题在于提交表单时,onSubmit或我的表单结构方法不正确。

这是CreateListing.js减速器,它会有所帮助:

const INITIAL_STATE= {
 isListingLoading: false,
 isListingCreated: false,
}
const CreateListing = (state = INITIAL_STATE, action) => {
 switch(action.type){
 case 'CREATE_LISTING_LOADING':
        return Object.assign({}, state, {isListingLoading: true});
 case 'CREATE_LISTING_SUBMIT_FORM':
        return Object.assign({}, state, {isListingCreated: true});
 default:
        return state;
} }
 export default CreateListing;

非常感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

如果表单中还有其他按钮,则应添加type="button"。 因此进行这样的更改。

      <button type="button" className="Button button-create is-red" onClick={this.props.onLoadingCreateListing}>
        CREATE LISTING
      </button>