首页 > 解决方案 > 使用 Redux 存储中的初始值填充 Redux-Form

问题描述

对于我的生活,我无法让我的 Redux-Form 填充初始值。我觉得我已经查看了那里的每个 SO 问题/答案,但到目前为止还没有任何帮助。

以下是我的代码的一些相关部分:

class Profile extends React.Component {

  render() {
    return (
      <form>
        <div>
          <Field type="text" name="firstName" label="First Name" component={rfField} />
        </div>
      </form>
    );
  }
}

const mapStateToProps = (state) => {
  return {
    initialValues: {
      firstName: state.getIn(['user', 'firstName'])
    }
  };
};

const profileForm = reduxForm({
  form: 'profile',
  enableReinitialize: true
})(Profile);

const withConnect = connect(mapStateToProps);
const withReducer = injectReducer({ key: 'profile', reducer });
const withSaga = injectSaga({ key: 'profile', saga });

export default compose(withReducer, withSaga, withConnect)(profileForm);

该状态具有我从中获取的值mapStateToProps,但是该字段不显示初始值;它仍然是空的。如果我state.getIn(...)只更改为文字“测试”,则该字段保持为空。如果我转到initialValues调用reduxForm(...),仅使用“测试”而不是state.getIn(...),该firstName字段会正确显示“测试”。

我认为这与我使用 、 和 函数的reduxForm方式connect有关compose。这是 react-redux-boilerplate 项目的设置方式,所以我只是使用该范例。

我绝对不是 React/Redux 专家,所以如果需要任何其他信息,请告诉我。谢谢!

来自 package.json:

react: 16.4.0
redux: 4.0.0
react-redux: 5.0.7
redux-form: 7.4.2

标签: reactjsreduxreact-reduxredux-form

解决方案


再次更新!

由于它似乎mapStateToProps是异步设置的,因此您需要在方法state中结合使用 React 。this.props.initialize()componentDidUpdate

(或您在状态中命名的this.props.formFields任何名称Redux)需要遵循Field's中指定的相同命名约定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.isLoadingfalse,然后提示使用this.props.formFields数据初始化 Redux 表单字段。

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)
);

动作/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
});

推荐阅读