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 whateve
For a stateless functional component, you can do it like this:
componentWillMount() {
this.props.initialize({ discountCodes: ["ABC200", "XYZ500"] });
}
For a class, you can do it like this:
const mapStateToProps = state => (
{
initialValues: {
discountCodes: ["ABC200", "XYZ500"]
}
);
So, you're trying:
initialValues
)Whilst @FurkanO might work, I think the best approach is to load the form when you got all async data, you can do that by creating a parent component / container:
UserEditLoader.jsx
componentDidMount() {
// I think this one fits best for your case, otherwise just switch it to
// componentDidUpdate
apiCalls();
}
/* api methods here */
render() {
const { profile } = this.props;
return (
{profile && <UserEdit profile={profile} />}
);
}
Basically what you should be doing in the UserEditLoader
is to execute the API functions and update the state (or props if redux connected). Whenever the profile variable isn't empty (meaning you got the data you were expecting) then mount UserEdit
with profile as prop.
If the enableReinitialize : true
trick does not work, you can update each field when the initialValues
prop changes.
componentWillReceiveProps(nextProps) {
const { change, initialValues } = this.props
const values = nextProps.initialValues;
if(initialValues !== values){
for (var key in values) {
if (values.hasOwnProperty(key)) {
change(key,values[key]);
}
}
}
}
I have never worked with FieldsArray
but I assume this would not work here.
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.
initialize() is a prop provided by reduxForm, that can be used to fill up the form values.
change() is another prop provided by reduxFrom to change a field value.
import * as React from 'react';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
const submit = values => {
// print the form values to the console
console.log(values)
}
interface Props {
history?: any;
location?: any;
session?: any;
handleSubmit?: Function;
initialize?: Function;
change?: Function;
}
class ContactForm extends React.Component<Props, any> {
constructor(props, state) {
super(props, state);
this.state = {
value: ''
};
}
componentDidMount() {
const { initialize, session, location } = this.props;
console.log(location.pathname);
if (session && session.user) {
const values = {
firstName: session.user.name,
lastName: session.user.lastName,
email: session.user.email
};
initialize(values);
}
}
componentWillReceiveProps(nextProps) {
const { initialize, session } = this.props;
if (nextProps.session !== session) {
if (nextProps.session && nextProps.session.user) {
const values = {
firstName: nextProps.session.user.name,
lastName: nextProps.session.user.lastName,
email: nextProps.session.user.email
};
initialize(values);
} else {
const values = {
firstName: null,
lastName: null,
email: null
};
initialize(values);
}
}
}
render() {
const { handleSubmit, change } = this.props;
return (
<React.Fragment>
<form onSubmit={handleSubmit(submit)}>
<div>
<label htmlFor="firstName">First Name</label>
<Field name="firstName" component="input" type="text" />
</div>
<div>
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" component="input" type="text" />
</div>
<div>
<label htmlFor="email">Email</label>
<Field name="email" component="input" type="email" />
</div>
<button type="submit">Submit</button>
</form>
<input type="text" value={this.state.value}
onChange={(e) => {
this.setState({ value: e.target.value });
change('firstName', e.target.value);
}}
/>
</React.Fragment>
);
}
}
export default connect((state) => {
return {
session: state.session
}
},
{}
)(withRouter((reduxForm({
form: 'contact'
})(ContactForm))));
To set the initialValues
it is important to apply the reduxForm()
decorator before the connect()
decorator from redux. The fields will not populate from the store state if the order of the decorators is inverted.
const FormDecoratedComponent = reduxForm(...)(Component)
const ConnectedAndFormDecoratedComponent = connect(...)(FormDecoratedComponent)
If, in addition to setting the values for the first time, you need to re-populate the form every time the state changes then set enableReinitialize: true
Find a simple example in this answer.
Read the official documentation and full example.
Read about this issue here.