再次更新!
由于 mapStateToProps 似乎是异步设置的,因此您需要在 componentDidUpdate 方法中结合使用 React state 和 this.props.initialize()。
this.props.formFields(或您在Redux 状态下命名的任何名称)需要遵循Field 的name 中指定的相同命名约定。例如:{ firstName: "", lastName: "" } 应该匹配 <Field name="firstName" ... /> <Field name="lastName" .../>。
如果您计划允许用户编辑输入,您还需要keepDirtyOnReinitialize: true - 否则,不管输入显示什么,它都会提交初始化值。
工作示例:https://codesandbox.io/s/zm3mqw2m4
下面的示例在类的 componentDidMount 方法中触发 Redux 操作 (this.props.asyncFormFields),显示一个微调器,然后检查类的 componentDidUpdate 方法中的 this.props.formFields 是否已更改。如果 this.props.formFields 被更改,它会将 this.state.isLoading 设置为 false,然后提示使用 this.props.formFields 数据初始化 Redux Form 字段。
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 });
reducers/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
});