Redux form does not reset

7.6k views Asked by At

i have a component which based upon props renders a form with different components.

class Feedback extends Component {

submitMyForm(data) {
  const { onSubmit, reset } = this.props;
  reset();
  return  onSubmit(data);
//
  // do other success stuff

}

render() {
  const { handleSubmit } = this.props;
  let component;

  if(this.props.data.feedbackType == "likert")
    component =  Likert;
  else if(this.props.data.feedbackType == "single choice")
    component =  SingleChoice;
  else if(this.props.data.feedbackType == "multiple choice")
    component =  MultipleChoice;


return (
  <div>
      <h1>Feedback zu Aufgabe {this.props.id}</h1>
      <form onSubmit={handleSubmit(this.submitMyForm.bind(this))}>
        <Field
          name="feedback"
          component={component}
          heading={this.props.data.description}
          items={this.props.data.options}
          required={true}
        />
        <button type="submit">Submit</button>
      </form>
  </div>

 );
}
}

    // Decorate the form component
   Feedback = reduxForm({
    form: 'feedback', // a unique name for this form,
    validate,
    enableReinitialize:true
  })(Feedback);

function validate(formProps) {
  const errors = {};

  if (!formProps.feedback) {
    errors.feedback = 'please select an option';
  }


  return errors;
}


export default Feedback;

import React, { PropTypes } from 'react';

const SingleChoice = ({ input, disabled, heading, required, className, items, name, meta: { touched, error } }) => (
    <fieldset className={`form__field ${className || ''}`}>

        <legend className="form__label">
            {heading}{required ? (<span>*</span>) : null}
            { (touched && error) ? (
                <span className="form__error"> {error}</span>
            ) : null }
        </legend>

        <div>
        { items.map((item, i) => (
            <div className="form__segmented-control width-1/2@small" key={ i }>
                <input
                    {...input}
                    name={ name }
                    type="radio"
                    value={ item.value }
                    disabled={ disabled }
                    className="segmented-control__input u-option-bg-current"
                    id={ `${name}-${item.value}` }
                />
                <label className="segmented-control__label u-adjacent-current" htmlFor={ `${name}-${item.value}` }>
                    {item.label}
                </label>
            </div>
        ))
        }
        </div>
    </fieldset>
);

SingleChoice.propTypes = {
    input: PropTypes.object.isRequired,
    name: PropTypes.string.isRequired,
    className: PropTypes.string,
    items: PropTypes.arrayOf(PropTypes.shape({
        label: PropTypes.string.isRequired,
        value: PropTypes.any.isRequired,
    })).isRequired,
    heading: PropTypes.string,
    meta: PropTypes.object,
    required: PropTypes.bool,
    disabled: PropTypes.bool,
};

export default SingleChoice;

The first time the form renders everything is fine. All radio buttons are unchecked and if i try to submit it i get an validation error as intended. But when my Feeback component receives new props and the form is updated. The old values still remain selected when the form component for the new props is the same as the one for the old props.

When the form component for the new props is different all values are not selected as intended, but i can submit the form without selecting anything, which should be prevented by validation.

I hope you got any suggestions, i am totally out of ideas at this point.

3

There are 3 answers

0
Anthony On BEST ANSWER

I searched for hours trying to find a resolution to this problem. The best way I could fix it was by using the plugin() API to teach the redux-form reducer to respond to the action dispatched when your submission succeeds. Exactly like the first step here How can I clear my form after my submission succeeds?

const reducers = {
  // ... your other reducers here ...
  form: formReducer.plugin({
  nameOfTheForm: (state, action) => { // <- 'nameOfTheForm' is name of form 
    switch(action.type) {
      case ACCOUNT_SAVE_SUCCESS:
        const values = undefined;
        const fields = {
          fields: {
            input_field_name: {
              visited: false,
              touched: false
            }
            // repeat for each input field
          }
        };
        const newState = { ...state, values, fields };
        return newState;           
      default:
        return state;
      }
    }
  })
}

You will have to change a couple things in your component.

onSubmit(values) {
  this.props.postForm(values, () => {});
}

render(){
  const { handleSubmit } = this.props;
}

return (
  <form onSubmit={handleSubmit(this.onSubmit.bind(this))}></form>
)

In your actions file:

export function postForm(values, callback) {
  const request = axios.get(`${ROOT_URL}`, config).then(() => callback());
  return {
    type: ACCOUNT_SAVE_SUCCESS,
    payload: request
  };
}
0
gustavohenke On

when my Feeback component receives new props and the form is updated, the old values still remain selected when the form component for the new props is the same as the one for the old props.

This is because the values for the feedback form are stored in your Redux store.
You should implement componentWillReceiveProps and test whether your form should be reset or not.

class Feedback extends Component {
  componentWillReceiveProps ( nextProps ) {
    if ( nextProps.blabla !== this.props.blabla ) {
      // oh cool, props changed, let's reset the form
      // checkout more available form props at http://redux-form.com/6.4.3/docs/api/ReduxForm.md/
      this.props.reset();
    }
  }

  render () {
    // your normal rendering function
  }
}
0
Pibo On

The best way I found:

import 'initialize'...

import {initialize} from 'redux-form';

and then when you call the action, call another action right after passing an empty object to the 'initialize' function...

  yourFunction = (data) => {
    this.props.dispatch(yourAction(data))
    .then(
      result => {
        if (result) {
          this.props.dispatch(initialize('nameOfTheForm', {}));
        }
      }
    );