7
votes

I'm creating multiple forms within a single component and to initialize them with the redux store I'm defining the form's name attribute in the<form> element, as opposed to within the reduxForm() helper, which was documented here...

How to embed the same redux-form multiple times on a page?

I'm creating the forms from the 'listing' object and passing it to my components with mapStateToProps(). I'm trying to set the initial values of the form with initialValues={}, but Redux Form is producing the following errors and is asking for the form to be declared in the reduxForm() helper...

1) Failed prop type: The prop form is marked as required in Form(ItemInfo), but its value is undefined.

2) Unknown prop initialValues on tag. Remove this prop from the element.

And this appears to be similar to the issue mentioned here...

https://github.com/erikras/redux-form/issues/28

import _ from 'lodash';
import React, { Component } from 'react';
import { reduxForm, Field } from 'redux-form';
import { connect } from 'react-redux';
import * as actions from '../../../actions';
import {Col} from 'react-grid-system';
import RaisedButton from 'material-ui/RaisedButton';

class ItemInfo extends Component {

  renderSingleItem(item){
    let theItem =  _.map(_.omit(item, '_id'), (value,field) => {
        return (
          <div key={field}>
            <label>{field}</label>
            <Field component="input" type="text" name={field} style={{ marginBottom: '5px' }} />
            <div className="red-text" style={{ marginBottom: '20px' }}>
            </div>
          </div>
        );
      });
    return theItem || <div></div>;
  }

  renderItemInfo() {

      if (this.props.listing.listing !== undefined) {
        let theItems = _.map(this.props.listing.listing.items, item => {                
            return (
                <Col key={item._id} md={3}>
                  <form form={`editItemInfo_${item._id}`} initialValues={item}>
                    {this.renderSingleItem(item)}
                    <RaisedButton secondary={true} label="Remove Item"/>
                    <RaisedButton primary={true} label="Update Item"/>
                  </form>
                </Col>
            );
        });
        return theItems || <div></div>;
      }

  }

  render() {
    return (
        <div className="row">
            {this.renderItemInfo()}
        </div>
    );
  }
}

function mapStateToProps({listing}) {
  return { listing };
}

ItemInfo = reduxForm({
  fields: ["text"],
  enableReinitialize: true
})(ItemInfo)

ItemInfo = connect(mapStateToProps,actions)(ItemInfo)

export default ItemInfo

This is an example of the 'listing' object being returned...

{ _id: 59b5eebd33a3a833b6ac1386,
  _user: 59aff09a11011f0cfd8d7666,
  location: 'nother',
  availability: 'jhkvljh',
  price: 9860,
  __v: 0,
  items:
   [ { equipmentType: 'kbj;kj',
       make: ';jb',
       model: ';;jb',
       watts: 9860,
       bulb: 'kjbkj',
       condition: 'kjbkjb',
       _id: 59b5eebd33a3a833b6ac1387 },
     { condition: 'houy',
       bulb: 'jhg',
       watts: 8907,
       model: 'mode',
       make: 'maker',
       equipmentType: 'smoquip',
       _id: 59b5f9cf13b37234ed033a75 } ] }

Thanks for your help!

1

1 Answers

6
votes

I finally figured out a work-around with a little hack. It appears that this is one part a bug with Redux Form and one part error with my initial implementation.


Correct Implementation

As detailed by @erikras, Redux Form creator... enter image description here https://github.com/erikras/redux-form/issues/28

The form config parameter needs to be passed to a decorated component and not to a jsx <form> component. To do this I refactored my form into an imported child component and mapped over these instead...

 renderItemForms() {
    if (this.props.listing.listing !== undefined) {
      return _.map(this.props.listing.listing.items, item => {
          return (
            <ItemInfo form={`editItemInfo_${item._id}`} initialValues={item} key={item._id} item={item} /> 
          );
      });
    }
  }



Redux Form Bug

The above implementation will connect your forms to the redux store properly, but it will still create a 'Failed prop type: The prop form is marked as required' error that will break your views. The solution I found is to stick any random string in the 'form' property of the redux-form options to prevent the error...

ItemInfo = reduxForm({
  form: 'any random string here',
  fields: ["text"],
  enableReinitialize: true
})(ItemInfo)

The second error message for initialValues was only subsequent to the first 'form parameter' error so now everything is error free and in Redux dev tools I can confirm that the in-line form property is overriding the property from reduxForm() options. Forms are now successfully being managed by the redux store with the correct 'form name/id'...

enter image description here



I hope this helps save someone else a headache minor. Please excuse any incorrect terminology in my explanation above, I'm still a Redux/React noob, but if anyone want more details Im happy to provide more details on my implementation.