dagda1
dagda1

Reputation: 28770

Form input using Redux Form not updating

My input field is not updating on key press:

import React, { Component, PropTypes } from 'react';

import { Field, reduxForm } from 'redux-form';

class CitySelector extends Component {
  render() {
    const { isFetching, pristine, submitting, handleSubmit } = this.props;

    return (
      <form className="form-horizontal col-xs-offset-1" onSubmit={handleSubmit(this.fetchWeather)}>
        <div className="form-group">
          <div className="col-md-4 col-xs-4">
            <Field name="city"
                   component={city =>
                     <input type="text" className="form-control" {...city.input} placeholder="enter a city for a 5 day forecast"/>
                   }
            />
          </div>
          <div className="col-md-3 col-xs-3">
            <button type="submit" className="btn btn-success">Submit</button>
          </div>
        </div>
      </form>
    );
  }
}

export default reduxForm({
  form: 'cityForm'
})(CitySelector);

Do I need to supply an onChange handler for text inputs?

Upvotes: 22

Views: 21892

Answers (5)

Finelf
Finelf

Reputation: 11

I found out/ my problem was my

form: formReducer

was not in rootReducer.

formReducer must be on top. My case:

const rootReducer = combineReducers({
   general: generalReducer,
   data: combineReducers({
       user:userReducer,
       todoReducer
   }),
       form: formReducer
   });

Upvotes: 0

agm1984
agm1984

Reputation: 17132

I was just having an issue similar to this question, except my form wasn't submitting and my validate function also wasn't firing.

It was due to this:

I changed it from input to something else and it totally broke redux-form SILENTLY

const TextInput = ({
    input,                                                 <--- DO NOT CHANGE THIS
    placeholder,
    type,
    meta: { touched, error, warning }
  }) => {
    return (
      <div className="row-md">
          <input
            placeholder={placeholder}
            type={type}
            className="form-text-input primary-border"
            {...input}                                     <--- OR THIS
          />
          {touched && ((error && <span>{error}</span>) || (warning && <span>{warning}</span>))}
      </div>
    )
}

Here's the rest of my input if anyone wants to study it:

<Field
  component={TextInput}
  type="tel"
  name="person_tel"
  placeholder="Mobile Phone Number"
  value={this.props.person_tel}
  onChange={(value) => this.props.updateField({ prop: 'person_tel', value })}
/>

Upvotes: 3

Aref Aslani
Aref Aslani

Reputation: 1636

If you are using immutable data structures, instead of:

import { reduxForm } from 'redux-form';

use this:

import { reduxForm } from 'redux-form/immutable';

See here for more info http://redux-form.com/6.7.0/examples/immutable/

Upvotes: 27

rafaelbiten
rafaelbiten

Reputation: 6240

I was having the same problem and my mistake was very simple.

Here's what I had:

import { combineReducers } from 'redux';
import { reducer as forms } from 'redux-form';

import otherReducer from './otherReducer';

export default combineReducers({ otherReducer, forms });

Notice that I was importing redux-form reducer as forms and passing it as is to my combineReducers (like I did with otherReducer) using ES6 Object property value shorthand.

The problem is that the key used to pass redux-form reducer to our combineReducers MUST be named form, so we have to change it to:

export default combineReducers({ customer, form: forms });

or

import { reducer as form } from 'redux-form';
export default combineReducers({ otherReducer, form });

Hope this helps someone else...

Upvotes: 73

Konstantin Grushetsky
Konstantin Grushetsky

Reputation: 1062

If you supply a custom input component to the Field, then yes you have to call onChange passed within input prop to your component. In fact, you almost got it right by spreading city.input, but there's a catch.

When you define a stateless component (or just any function) inside render() method, it is recreated upon every render. And because this stateless component is passed as a prop (component) to Field, it forces Field to render after each recreation. So, your input is going to lose focus whenever CitySelector component renders, thus, no key presses will be captured.

You should extract your stateless component into a separate definition:

const myInput = ({ input }) => (
  <input type="text" className="form-control" {...input} placeholder="enter a city for a 5 day forecast" />
);

class CitySelector extends Component {
  render() {
    const { isFetching, pristine, submitting, handleSubmit } = this.props;

    return (
      <form className="form-horizontal col-xs-offset-1" onSubmit={handleSubmit(this.fetchWeather)}>
        <div className="form-group">
          <div className="col-md-4 col-xs-4">
            <Field name="city" component={myInput} />
          </div>
          <div className="col-md-3 col-xs-3">
            <button type="submit" className="btn btn-success">Submit</button>
          </div>
        </div>
      </form>
    );
  }
}

It also makes your code more legible.

You can find more info on that problem in official docs of Redux Form. Note that you could probably use the default input without creating your own, take a look at simple form example.

Upvotes: 1

Related Questions