ВНОВЬ ОБНОВЛЕНО!
Поскольку кажется, что mapStateToProps
устанавливается асинхронно, вам необходимо использовать React state
в сочетании с this.props.initialize()
в методе componentDidUpdate
.
this.props.formFields
(или как вы его называете в состоянии Redux
) должно следовать тому же соглашению об именах, указанному в Field
'name
.Например: { firstName: "", lastName: "" }
должно соответствовать <Field name="firstName" ... />
<Field name="lastName" .../>
.
Вам также понадобится keepDirtyOnReinitialize: true
, если вы планируете разрешить пользователю редактировать входные данные - в противном случае, несмотря на то, что отображается на входе, он отправит инициализированное значение.
Рабочий пример: https://codesandbox.io/s/zm3mqw2m4
В приведенном ниже примере запускается действие Redux (this.props.asyncFormFields
) в методе componentDidMount
класса, отображается счетчик, а затем проверяется, было ли this.props.formFields
изменено в методе класса componentDidUpdate
.Если this.props.formFields
был изменен, он устанавливает this.state.isLoading
в false
, а затем предлагает поля Redux Form инициализироваться данными this.props.formFields
.
SimpleForm.js
import React, { Component } from "react";
import { reduxForm } from "redux-form";
import { connect } from "react-redux";
import { asyncFormFields } from "../actions";
import ShowError from "../components/ShowError";
import ShowForm from "../components/ShowForm";
import Spinner from "../components/Spinner";
class SimpleForm extends Component {
state = {
err: "",
isLoading: true
};
componentDidUpdate = (prevProps, prevState) => {
if (this.props.formFields !== prevProps.formFields) {
this.setState({ isLoading: false }, () =>
this.props.initialize({ ...this.props.formFields })
);
}
};
componentDidMount = () => this.props.asyncFormFields();
reinitializeForm = () =>
this.setState({ isLoading: true }, () => this.props.asyncFormFields());
render = () =>
this.props.err ? (
<ShowError err={this.props.err} />
) : this.state.isLoading ? (
<Spinner />
) : (
<ShowForm {...this.props} reinitializeForm={this.reinitializeForm} />
);
}
export default reduxForm({
form: "SimpleForm",
enableReinitialize: true,
keepDirtyOnReinitialize: true
})(
connect(
state => ({ err: state.server, formFields: state.fields }),
{ asyncFormFields }
)(SimpleForm)
);
Другой способ инициализации формы Redux - использовать плагин ReduxForm formReducer
.Это немного сложнее и включает в себя больше шагов, но результат тот же:
Рабочий пример: https://codesandbox.io/s/xppnmklm7q
SimpleForm.js
import React, { Component } from "react";
import { reduxForm } from "redux-form";
import { connect } from "react-redux";
import { asyncFormFields, initForm } from "../actions";
import ShowError from "../components/ShowError";
import ShowForm from "../components/ShowForm";
import Spinner from "../components/Spinner";
class SimpleForm extends Component {
state = {
err: "",
isLoading: true
};
componentDidUpdate = (prevProps, prevState) => {
if (this.props.formFields !== prevProps.formFields) {
this.setState({ isLoading: false }, () => this.props.initForm(this.props.formFields));
}
};
componentDidMount = () => this.props.asyncFormFields();
reinitializeForm = () => this.setState({ isLoading: true }, () => this.props.asyncFormFields());
render = () =>
this.props.err
? <ShowError err={this.props.err} />
: this.state.isLoading
? <Spinner />
: <ShowForm {...this.props} reinitializeForm={this.reinitializeForm} />
);
}
export default reduxForm({
form: "SimpleForm",
enableReinitialize: true,
keepDirtyOnReinitialize: true
})(
connect(
state => ({ err: state.server, formFields: state.fields }),
{ asyncFormFields, initForm }
)(SimpleForm)
);
actions / index.js
import axios from "axios";
import { INIT_FORM, SET_FORMFIELDS, SERVER_ERROR } from "../types";
export const asyncFormFields = () => dispatch =>
axios
.get("https://randomuser.me/api/?nat=us&results=1")
.then(({ data: { results } }) =>
dispatch({
type: SET_FORMFIELDS,
payload: {
firstName: results[0].name.first,
lastName: results[0].name.last
}
})
)
.catch(err => dispatch({ type: SERVER_ERROR, payload: err }));
export const initForm = fields => ({ type: INIT_FORM, payload: fields });
Редукторы / index.js
import { createStore, combineReducers } from "redux";
import { reducer as formReducer } from "redux-form";
import { INIT_FORM, SET_FORMFIELDS, SERVER_ERROR } from "../types";
const fieldsReducer = (state = {}, { payload, type }) => {
switch (type) {
case SET_FORMFIELDS:
return { ...state, ...payload };
default:
return state;
}
};
const serverResponseReducer = (state = "", { payload, type }) => {
switch (type) {
case SERVER_ERROR:
return (state = payload);
default:
return state;
}
};
const formReducers = {
form: formReducer.plugin({
SimpleForm: (state, { payload, type }) => { // <----- 'SimpleForm' - name given to reduxForm()
switch (type) {
case INIT_FORM: // <----- action type triggered by componentDidUpdate from 'SimpleForm'
return {
...state, // <----- spreads out any previous form state (registered fields)
values: {
...payload // <----- initializes form fields values from supplied initForm action 'field' values
}
};
default:
return state;
}
}
})
};
export default combineReducers({
fields: fieldsReducer,
server: serverResponseReducer,
...formReducers
});