React-redux-form: Proper way to pre-fill input fields?

Created on 9 Apr 2016  路  15Comments  路  Source: davidkpiano/react-redux-form

Is it preferred to use action.merge to "load" object data into Redux, which will populate fields? Or is there some way to do it the other way around, where the field itself has a default value, and it sends it up to Redux automatically?

question

All 15 comments

Hey @ffxsam, you can do this the vanilla Redux way by just providing an initial state to either your modelReducer() or your existing modeled() reducer:

const initialState = {
  firstName: '',
  lastName: '',
};

// creating a store...
{
  user: modelReducer(user, initialState),
  user: modeled(userReducer), // existing user reducer with the initial state
}

You can also use actions.load(model, value) to "load" in the value of your model without triggering a "change" action. This is good when you want to initialize fields asynchronously.

I'll add documentation for this soon; it was a recent addition.

Thanks David! I guess that was my question.. if I hit "edit" to edit an item and I want to pre-populate the fields, <Field> doesn't do that automatically, correct? I have to use action.load or action.merge to copy the object into Redux?

Oh, it's because the controls are not connected. You can simply connect them yourself by doing something like this:

<Field model="foo.bar">
  <input value={foo.bar} />
</Field>

Duh. Why did I not think of that? Thanks :)

It's a good point that you brought up, though! I'm still debating whether controls inside <Field> should be _controlled_ by default. This might be able to work even if you have this:

<Field model="foo.bar"
  updateOn="blur">
  <input type="text" />
</Field>

because the value would be mapped to a string viewValue on the formReducer updated on every change, even if the model value on the modelReducer doesn't update on every change.

Only caveat: a formReducer for the model would be _required_ for this to work.

:+1: ? :-1: ?

This is probably a good thing. If a text field is linked to RRF, then it should most definitely be a controlled input. I can't think of a scenario where I'd want it not to be. But I hardly use <Field> as I usually make my own input components, and using createFieldClass to map props automatically makes your component controlled, via the props.modelValue, correct?

Yes, if you are mapping value: props.modelValue then it is setting the value=... prop of the control, thus controlling it.

Just to clarify this for anyone else reading it:

<Field model="foo.bar">
  <input value={foo.bar} />
</Field>

Obviously foo.bar would come up as an error. This should be a value coming from a Redux connect:

<Field model="foo.bar">
  <input value={this.props.bar} />
</Field>

...

export default connect(({ foo }) => ({
  bar: foo.bar,
})(MyComponent)

Sorry a newbie question here.

I am just flexing my muscles with React using with Meteor and have not attempted to use Redux yet (although I will).Ahead of doing this I have decided to use react-redux-form as a local form and then migrate to redux when I am more confident.

I have used the local form for an insert to a mongo database which is straight forward, however I want to now create a form for an update. Can I auto populate this from mongo or do I have to use Redux? If there are any examples of using RRF in local mode with mongo or even RRF with mongo hooked up as an update form I would be greatful if somebody could steer me in that direction.

I'm not sure about using it with Mongo (no experience in that) but you can load initial data (aka autopopulate) like so:

// add other props as needed
<LocalForm initialState={/* your initial state */}>
  // ...
</LocalForm>

I have tried this, but not had any joy - the field is not autopopulated. Any ideas where I am going wrong.

import React, {Component} from 'react';
import { LocalForm, Control } from 'react-redux-form';
import Scenes from '../collections/scene.js';


export default class SceneUpdateForm extends Component {
  constructor() {
      super();
      this.state = {
        scene: {set:"set22"}};
      console.log(this.state.scene.set);
    }

  //handleChange(values) { ... }
//handleUpdate(form) { ... }
handleSubmit(formvalues) {
  Scenes.update({
    sheet_no: formvalues.sheet_no,
    project_ID: formvalues.project_ID,
    scene_no: formvalues.scene_no,
  });
};

render() {
  return (
    <div>
      {this.props.count}
      <LocalForm
        initialState={this.state}
        model="scene"
        onSubmit={(values) => this.handleSubmit(values)}
      >
        <div className="field">
          <label>Sheet No:</label>
          <Control  type="number" model=".sheet_no" />
        </div>
        <div className="field">
          <label>Project ID:</label>
          <Control  type="number" model=".project_ID" />
        </div>
        <div className="field">
          <label>Scene Number:</label>
          <Control type="number" model=".scene_no" />
        </div>
        <div className="field">
          <label>Set:</label>
          <Control.text model=".set" />
        </div>

        <button type='submit'> Submit </button>
      </LocalForm>
  </div>
  );
}
}

Try initialState={this.state.scene}

Thanks so much David that works. I am now wanting to pass in state from a parent I have tried initialState={this.props.scene} but nothing appears. Any ideas?

Can you console.log(this.props.scene) - and see if it initially is null or something? If it's not initially null/undefined, it should work as expected.

Many thanks for the hand holding. the console log returns nothing initially but then returns the object...

``` Object
_id:"8GcLgtgygJq3dd5gf"
project_ID:"1"
scene_no:"1"
set:"SCENE 1"
sheet_no:1

Was this page helpful?
0 / 5 - 0 ratings