2017-03-11 3 views
0

두 가지 다른 오류가 나타납니다.Redux 연결/reduxForm은 렌더링하지 않습니다. 구성 요소

첫 번째는 reduxForm 메서드를 내보내는 것만으로 내 구성 요소/stateToProps/reduxForm을 모두 연결할 때입니다. 그것은 내가 정의되지 않은 소품 유형에 실패했다고 말합니다. 예를 들어

:

function mapStateToProps(state) { 
    const { account, priceBook } = state; 
    const accountId = account.id; 

    return { accountId, priceBook }; 
} 

export default reduxForm({ 
    form: 'createOrder', 
    destroyOnUnmount: false, 
    validate, 
}, mapStateToProps, { 
    getRevShareAction: getRevShare, 
    getPriceBookAction: getPriceBook, 
})(NewOrderFormFour); 

Warning: Failed prop type: The prop `getPriceBookAction` is marked as required in `NewOrderFormFour`, but its value is `undefined`. 

그래서이 문제를 해결하기 위해 나는 reduxForm을 분리하고 반응-REDUX의 연결 방법을 사용하여 소품을 연결합니다. 나는 그것이 렌더링 간단한 <div> 태그를 두 번째 인스턴스에 reduxForm을 주석하고 구성 요소에 렌더링하는 경우

Invariant Violation: Component(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object. 

:

NewOrderFormFour = reduxForm({ 
    form: 'createOrder', 
    destroyOnUnmount: false, 
    validate, 
}); 

export default connect(mapStateToProps, { 
    getRevShareAction: getRevShare, 
    getPriceBookAction: getPriceBook, 
})(NewOrderFormFour); 

말하는 오류를 반환합니다. 이 문제의 원인이 무엇인지 확신 할 수 없습니다. 오타 또는 잠재적 오류에 대해 구성 요소를 위아래로 조회했으며 아무 것도 의미가없는 것 같습니다. 당신은 단지 reduxForm과 장식 기능을 생성했지만 양식 구성 요소에 적용하지 않았다

import React, { PropTypes } from 'react'; 
import { reduxForm, Form, Field } from 'redux-form'; 
import { connect } from 'react-redux'; 

import { getClassName } from '../../utils/forms'; 
import { storeWithExpiration, getOrderTotalCost } from '../../utils/common'; 
import { getRevShare, getPriceBook } from '../../actions/pricing'; 

import DateTimePicker from 'react-widgets/lib/DateTimePicker'; 
import moment from 'moment'; 
import momentLocalizer from 'react-widgets/lib/localizers/moment'; 
momentLocalizer(moment); 

import ConfirmOrderDialog from './ConfirmOrderDialog'; 
import PriceBookTableContainer from '../pricing/PriceBookTableContainer'; 

const formats = [ 
    'MMM d yyyy', 
    'MMM d yy', 
    'd', 
]; 

export class NewOrderFormFour extends React.Component { 

    static propTypes = { 
    accountId: PropTypes.number.isRequired, 
    companyData: PropTypes.object, 
    cancelOrderFunction: PropTypes.func.isRequired, 
    closeDialogFunction: PropTypes.func.isRequired, 
    dataSets: PropTypes.object.isRequired, 
    dialog: PropTypes.object.isRequired, 
    escapeForm: PropTypes.func.isRequired, 
    fetchFieldsetsByIdFunction: PropTypes.func.isRequired, 
    formValues: PropTypes.object, 
    fieldSets: PropTypes.object.isRequired, 
    getPriceBookAction: PropTypes.func.isRequired, 
    getRevShareAction: PropTypes.func.isRequired, 
    handleSubmit: PropTypes.func.isRequired, 
    openDialogFunction: PropTypes.func.isRequired, 
    platformMap: PropTypes.object.isRequired, 
    previousPageFunction: PropTypes.func.isRequired, 
    priceBook: PropTypes.object.isRequired, 
    providerOrderNumber: PropTypes.string.isRequired, 
    providerCustomerNumber: PropTypes.string.isRequired, 
    renderInput: PropTypes.func.isRequired, 
    renderCompanyInfo: PropTypes.func.isRequired, 
    submitFunction: PropTypes.func.isRequired, 
    submitting: PropTypes.bool.isRequired, 
    useCaseMap: PropTypes.object.isRequired, 
    }; 

    createOrderFunction = (params) => { 
    const { openDialogFunction, submitFunction } = this.props; 

    openDialogFunction('confirmOrderDialog'); 
    submitFunction(params); 
    }; 

    handleStartDayChange = (param, startDay) => { 
    const { formValues: { endDay } } = this.props; 
    const endDayDate = new Date(moment(param).add(1, 'y').format()); 
    if (endDayDate) { 
     // endDay.value = endDayDate; 
     endDay.onChange(endDayDate); 
    } 
    return startDay.onChange(param); 
    } 

    handleEndDayChange = (param, endDay) => { 
    return endDay.onChange(param); 
    } 

    // Field manipulation is due to the fact that the calendar picker 
    // requires a date object, but react currently doesn't support 
    // passing objects as form values 
    openConfirmationDialog =() => { 
    const { openDialogFunction } = this.props; 
    let { formValues: { startDay, endDay } } = this.props; 

    const startDayString = JSON.stringify(startDay); 
    startDay = startDayString; 
    const endDayString = JSON.stringify(endDay); 
    endDay = endDayString; 
    openDialogFunction('confirmOrderDialog'); 
    } 

    render() { 
    const { 
     accountId, 
     dataSets, 
     dialog, 
     escapeForm, 
     fieldSets, 
     formValues, 
     formValues: { 
     platformCode, 
     numberOfSeats, 
     numberOfRecords, 
     }, 
     handleSubmit, 
     platformMap, 
     priceBook, 
     useCaseMap, 
     renderInput, 
     renderCompanyInfo, 
     submitting, 
     closeDialogFunction, 
     previousPageFunction, 
    } = this.props; 
    const isCRMTable = platformCode === 'SFDC'; 
    const pricebookData = isCRMTable ? priceBook.get('crmList') : priceBook.get('maList'); 
    const selectedPbData = pricebookData ? pricebookData.map(value => { 
     return { 
     floor: value.get('floor'), 
     min: value.get('min'), 
     max: value.get('max'), 
     }; 
    }).toArray() : null; 

    // If the user opens confirm dialog then cancels, we need to convert start and and dates 
    // from a string back to a date object 
    // Don't convert if dialog open 
    const dialogIsOpen = dialog.get('show'); 
    let { formValues: { startDay, endDay } } = this.props; 
    if (!dialogIsOpen) { 
     if (typeof startDay === 'string' && startDay.length > 0) { 
     startDay = new Date(JSON.parse(startDay)); 
     } 
     if (typeof endDay === 'string' && endDay.length > 0) { 
     endDay = new Date(JSON.parse(endDay)); 
     } 
    } 

    return (
     <div className="modal-wrap"> 
     <div className="container"> 
      <div className="card card-block"> 
      <span className="pull-right"> 
       <button 
       type="button" 
       className="btn btn-secondary escape" 
       onClick={() => escapeForm() } 
       > 
       <i className='fa fa-times'></i> 
       </button> 
      </span> 
      { renderCompanyInfo() } 
      <ul className="nav nav-tabs"> 
       <li className="nav-item"> 
       <a href="#" className="nav-link active">Select Existing SKU</a> 
       </li> 
       {/* <li className="nav-item"> 
       <a href="#" className="nav-link">Clone & Edit an Existing Order</a> 
       </li> */} 
      </ul> 
      <Form id="createOrder" onSubmit={ handleSubmit(this.openConfirmationDialog.bind(this))}> 
       <fieldset> 
       <div className="card card-block order-card"> 
        <h3 className="card-title"> 
        </h3> 
        <p className="card-text"> 
        <strong> 
         Select a List, and then a SKU&nbsp; 
        </strong> 
        </p> 
        <div className="form-group"> 
        <div className="form-group row"> 
         <div className="col-md-6"> 
         <div className="form-group"> 
          <Field 
          name="listId" 
          component={ this.renderGenericField } 
          label="List" 
          /> 
         </div> 
         </div> 
         <div className="col-md-6"> 
         <span className="col-sm-10 pull-right"> 
          <button 
          type="button" 
          className="btn btn-secondary btn-back" 
          onClick={ previousPageFunction } 
          > 
          Back 
          </button> 
          <button 
          type="submit" 
          className="btn btn-primary" 
          disabled={ submitting } 
          > 
          Place Order 
          </button> 
         </span> 
         </div> 
        </div> 
        </div> 
       </div> 
       </fieldset> 
      </Form> 
      <PriceBookTableContainer 
       accountId={ accountId } 
       dialog={ dialog } 
       isDAdmin={ false } 
       isCRM={ isCRMTable } 
       isPAdmin={ false } 
       tableContents={ isCRMTable ? priceBook.get('crmList') : priceBook.get('maList') } 
       revShare={ priceBook.get('revShare') } 
       openDialogFunction={() => { 
       } } 
       closeDialogFunction={() => { 
       } } 
       updatePriceAction={() => { 
       } } 
      /> 
      </div> 
     </div> 
     { dialog.id === 'confirmOrderDialog' && dialog.show ? 
      <ConfirmOrderDialog 
      dataSets={ dataSets } 
      dialog={ dialog } 
      formValues={ formValues } 
      fieldSets={ fieldSets } 
      selectedPbData={ selectedPbData } 
      platformMap={ platformMap } 
      useCaseMap={ useCaseMap } 
      closeDialogFunction={ closeDialogFunction } 
      submitOrderFunction={ this.createOrderFunction } 
      /> : null } 
     </div> 
    ); 
    } 

    renderGenericField = ({ input, label, meta: { touched, error } }) => { 
    return (
     <div className={ getClassName(touched, error) }> 
     <label className="form-control-label row"> 
      {label}:&nbsp; 
      { touched && error && <span> | {error} </span> } 
     </label> 
     { this.renderSpecialInput(label, input) } 
     </div> 
    ); 
    } 

    renderSpecialInput = (label, input) => { 
    if (label === 'List') { 
     return this.renderListIdSelect(input); 
    } 
    else if (label === 'SKU') { 
     return this.renderSkuIdSelect(input); 
    } 
    else if (label === 'Start date') { 
     return this.renderDateTimeInput(
     this.handleStartDayChange, 
     ((typeof input === 'string') ? null : input) 
    ); 
    } 
    else if (label === 'End date') { 
     return this.renderDateTimeInput(
     this.handleEndDayChange, 
     ((typeof input === 'string') ? null : input) 
    ); 
    } 
    return null; 
    } 

    renderDateTimeInput = (changeMethod, value) => { 
    const date = new Date(); 
    return (
     <div className="form-group row"> 
     <div className="col-sm-10"> 
      <DateTimePicker 
      time={ false } 
      min={ date } 
      parse={ formats } 
      onChange={ param => changeMethod(param) } 
      value={ value } 
      /> 
     </div> 
     </div> 
    ); 
    } 

    renderListIdSelect = (input) => { 
    const { fetchFieldsetsByIdFunction, dataSets } = this.props; 
    return (
     <select 
     {...input} 
     onChange={(event) => { 
      input.onChange(event); 
      const dataset = JSON.parse(event.target.value); 
      fetchFieldsetsByIdFunction(dataset.id, 
      'SKU', 
      storeWithExpiration.get('token')); 
     }} 
     className="form-control form-control-lg form-control-success" 
     autoFocus 
     > 
     <option value="">&lt; Please Select &gt;</option> 
     { dataSets.size > 0 ? 
      dataSets.valueSeq().map(this.renderDataSetItem) : null } 
     </select> 
    ); 
    } 

    renderSkuIdSelect = (input) => { 
    const { fieldSets } = this.props; 
    return (
     <select 
     {...input} 
     className="form-control form-control-lg form-control-success" 
     value={input || ''} 
     > 
     <option value="">&lt; Please Select &gt;</option> 
     { fieldSets.size > 0 ? 
      fieldSets.valueSeq().map(this.renderItem) 
      : 
      <option value="-1">No SKU's found</option> } 
     </select> 
    ); 
    } 

    renderDataSetItem = (item) => { 
    // Only render lists that are live (pending lists don't have SKUs) 
    if (item.status !== 0) { 
     return this.renderItem(item); 
    } 

    return null; 
    } 

    renderItem = (item) => { 
    return (
     <option key={ item.id } value={ JSON.stringify(item) }>{ item.name }</option> 
    ); 
    } 

    componentWillMount =() => { 
    const { 
     accountId, 
     getRevShareAction, 
     getPriceBookAction } = this.props; 
    let { formValues: { startDay, endDay } } = this.props; 

    const token = storeWithExpiration.get('token'); 

    getPriceBookAction(accountId, token); 
    getRevShareAction(accountId, token); 

    startDay = null; 
    endDay = null; 
    } 
} 

const validate = values => { 
    const isCRM = values.platformCode === 'SFDC'; 
    const today = new Date(moment().set('hour', 0).set('minute', 0).set('second', 0).format()); 
    const onMonthFromNow = new Date(moment(today).add(1, 'M').format()); 
    let oneMonthFromStartDate = onMonthFromNow; 
    if (values.startDay) { 
    oneMonthFromStartDate = new Date(moment(values.startDay).add(1, 'M').format()); 
    } 
    const errors = {}; 
    if (!values.listId || values.listId === '') { 
    errors.listId = 'Required'; 
    } 
    if (!values.skuId || values.skuId === '') { 
    errors.skuId = 'Required'; 
    } 
    else if (values.skuId === '-1') { 
    errors.skuId = 'Please Select a List With a SKU and Try Again'; 
    } 
    // Credits 
    if (!values.recordCredits || values.recordCredits === '') { 
    errors.recordCredits = 'Required'; 
    } 
    else if (isNaN(Number(values.recordCredits))) { 
    errors.recordCredits = 'Must be a number'; 
    } 
    else if (Number(values.recordCredits) < 1) { 
    errors.recordCredits = 'Must be greater than 0'; 
    } 
    else if (parseInt(values.recordCredits, 10) !== Number(values.recordCredits)) { 
    errors.recordCredits = 'Should be an integer'; 
    } 
    // Number of seats 
    // Nested if statements seem to break validate function. Using workaround 
    if (!isCRM) { 
    // Don't validate Number of seats 
    } 
    else if (!values.numberOfSeats || values.numberOfSeats === '') { 
    errors.numberOfSeats = 'Required'; 
    } 
    else if (isNaN(Number(values.numberOfSeats))) { 
    errors.numberOfSeats = 'Must be a number'; 
    } 
    else if (Number(values.numberOfSeats) < 1) { 
    errors.numberOfSeats = 'Must be greater than 0'; 
    } 
    else if (parseInt(values.numberOfSeats, 10) !== Number(values.numberOfSeats)) { 
    errors.numberOfSeats = 'Should be an integer'; 
    } 
    else if (parseInt(values.numberOfSeats, 10) > 1000) { 
    errors.numberOfSeats = 'Please contact Datarista for orders over 1000'; 
    } 
    // Number of records 
    if (isCRM) { 
    // Don't validate Number of records 
    } 
    else if (!isCRM && !values.numberOfRecords || values.numberOfRecords === '') { 
    errors.numberOfRecords = 'Required'; 
    } 
    else if (isNaN(Number(values.numberOfRecords))) { 
    errors.numberOfRecords = 'Must be a number'; 
    } 
    else if (Number(values.numberOfRecords) < 1) { 
    errors.numberOfRecords = 'Must be greater than 0'; 
    } 
    else if (parseInt(values.numberOfRecords, 10) !== Number(values.numberOfRecords)) { 
    errors.numberOfRecords = 'Should be an integer'; 
    } 
    else if (parseInt(values.numberOfRecords, 10) > 50000) { 
    errors.numberOfRecords = 'Please contact Datarista for orders over 50,000k'; 
    } 
    // Start and end times 
    if (values.endDay === null || values.endDay === undefined) { 
    errors.endDay = 'Required'; 
    } 
    else if (values.endDay < onMonthFromNow) { 
    errors.endDay = '1 month Minimum Contract Required'; 
    } 
    else if (values.endDay < oneMonthFromStartDate) { 
    errors.endDay = '1 month Minimum Contract Required'; 
    } 
    if (values.startDay === null || values.startDay === undefined) { 
    errors.startDay = 'Required'; 
    } 
    else if (values.startDay < today) { 
    errors.startDay = 'Start date can\'t be before today'; 
    } 
    else if (values.startDay >= values.endDay) { 
    errors.startDay = 'Must preceed end date'; 
    errors.endDay = 'Must follow start date'; 
    } 
    return errors; 
}; 

function mapStateToProps(state) { 
    const { account, priceBook } = state; 
    const accountId = account.id; 

    return { accountId, priceBook }; 
} 

NewOrderFormFour = reduxForm({ 
    form: 'createOrder', 
    destroyOnUnmount: false, 
    validate, 
}); 

export default connect(mapStateToProps, { 
    getRevShareAction: getRevShare, 
    getPriceBookAction: getPriceBook, 
})(NewOrderFormFour); 

답변

2

:

여기에 전체 구성 요소입니다. 대신이의

NewOrderFormFour = reduxForm({ 
    form: 'createOrder', 
    destroyOnUnmount: false, 
    validate, 
})(NewOrderFormFour); 

을 : reduxForm는이 같은 somethig에를 사용해야합니다 호출 인수로 구성 요소를 반응한다 장식 기능을 생성

+0

덕분에 너무 ... 내가 잊고 알았

NewOrderFormFour = reduxForm({ form: 'createOrder', destroyOnUnmount: false, validate, }); 
어떤 것. 나는 내가 이미 그렇게했다고 생각한다고 맹세하지만, 나는 그것을 놓쳤을 것임에 틀림 없다. 다시 한번 감사드립니다. –

+0

당신을 환영합니다. 내가 널 도울 수있어 기뻐. :) –

관련 문제