I'm trying to fill the profile form with data from API. Unfortunately redux-form doesn't want to cooperate with me in this case. For some reason fields stays empty whatever I do.
Setting the fixed values instead of values passed from reducer work well for some reason.
Maybe this is because I'm using redux-promise for API calls inside the action creators? How can I live with it and get rid of this. Here is my form component.
import React, { Component } from 'react'; import { reduxForm, Field } from 'redux-form'; import { connect } from 'react-redux'; import { fetchRoleList, fetchUserData } from '../actions'; class UserEdit extends Component { componentWillMount() { this.props.fetchRoleList(); this.props.fetchUserData(); } handleEditProfileFormSubmit(formProps) { console.log(formProps); } getRoleOptions(selected_id) { if (!this.props.profile) { return <option>No data</option>; } return this.props.profile.roles.map(role => { return <option key={role.role_id} value={role.role_id}>{role.name}</option>; }); } renderField(props) { const { input, placeholder, label, value, type, meta: { touched, error } } = props; return ( <fieldset className={`form-group ${ (touched && error) ? 'has-error' : '' }`}> <label>{label}</label> <input className="form-control" {...input} type={type} placeholder={placeholder} /> {touched && error && <div className="error">{error}</div>} </fieldset> ); } renderSelect({ input, placeholder, options, label, type, meta: { touched, error } }) { return ( <fieldset className={`form-group ${ (touched && error) ? 'has-error' : '' }`}> <label>{label}</label> <select className="form-control" {...input}> {options} </select> {touched && error && <div className="error">{error}</div>} </fieldset> ); } render() { const { handleSubmit } = this.props; const user = this.props.profile.user; return ( <div> {user ? user.email : ''} <form onSubmit={handleSubmit(this.handleEditProfileFormSubmit.bind(this))}> <Field name="email" label="Email:" component={this.renderField} type="text" placeholder="[email protected]" className="form-control"/> <Field name="name" label="Name:" component={this.renderField} type="text" placeholder="John Doe" className="form-control"/> <Field name="role" label="Role:" component={this.renderSelect} type="select" className="form-control" options={this.getRoleOptions()}/> <button action="submit" className="btn btn-primary">Edit user</button> <Field name="password" label="Password:" component={this.renderField} type="password" className="form-control"/> <Field name="passwordConfirm" label="Confirm Password:" component={this.renderField} type="password" className="form-control"/> { this.props.errorMessage && <div className="alert alert-danger"> <strong>Oops!</strong> {this.props.errorMessage} </div> } <button action="submit" className="btn btn-primary">Sign up!</button> </form> </div> ); } } let InitializeFromStateForm = reduxForm({ form: 'initializeFromState' })(UserEdit); InitializeFromStateForm = connect( state => ({ profile: state.profile, initialValues: state.profile.user }), { fetchRoleList, fetchUserData } )(InitializeFromStateForm); export default InitializeFromStateForm;
I do believe action creator will be useful as well:
export function fetchUserData(user_id) { user_id = user_id ? user_id : ''; const authorization = localStorage.getItem('token'); const request = axios.get(`${ROOT_URL}/user/${user_id}`, { headers: { authorization } }); return { type: FETCH_USER, payload: request }; }
To populate your form with initial values, you'll need to pass data to your form from your store. To do this, in your mapStateToProps() function, create a key called initialValues that is set to an object that contains the keys and values of the data you'd like to place in your form.
pristine means that no fields in the form have been modified yet. Perhaps you won't be able to find an exact definition of it in docs, but there is a similar terminology in Angular. You can find some details here or here. submitting , as the name suggests, means that the form is in process of submitting.
In Redux, a reducer is a pure function that takes an action and the previous state of the application and returns the new state. The action describes what happened and it is the reducer's job to return the new state based on that action.
You need to add enableReinitialize: true
as below.
let InitializeFromStateForm = reduxForm({ form: 'initializeFromState', enableReinitialize : true // this is needed!! })(UserEdit)
If your initialValues prop gets updated, your form will update too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With