使用Redux存储中的初始值填充Redux-Form

时间:2018-09-27 15:44:35

标签: reactjs redux react-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(...)更改为原义的'test',则该字段保持为空。如果我将initialValues移至reduxForm(...)调用,仅使用'test'而不是state.getIn(...),则firstName字段将正确显示'test'。

我认为它与我使用reduxFormconnectcompose函数的方式有关。这是设置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

2 个答案:

答案 0 :(得分:1)

再次更新!

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

this.props.formFields(或在Redux状态下使用的任何名称)都需要遵循Field的{​​{1}}中指定的相同命名约定。例如:name应该与{ firstName: "", lastName: "" } <Field name="firstName" ... />相匹配。

如果您打算允许用户编辑输入,则还需要<Field name="lastName" .../>,否则,尽管输入显示了内容,它将提交初始化值。

工作示例:https://codesandbox.io/s/zm3mqw2m4

下面的示例在类的keepDirtyOnReinitialize: true方法中触发Redux动作(this.props.asyncFormFields),显示微调器,然后检查类componentDidMount中的this.props.formFields是否已更改方法。如果更改了componentDidUpdate,它将this.props.formFields设置为this.state.isLoading,然后提示要使用false数据初始化Redux Form字段。

SimpleForm.js

this.props.formFields

初始化Redux表单的另一种方法是使用ReduxForm的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) ); 插件。这有点复杂,涉及更多步骤,但是结果是相同的:

工作示例:https://codesandbox.io/s/xppnmklm7q

SimpleForm.js

formReducer

actions / index.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)
);

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

答案 1 :(得分:0)

本周,我最终使用Redux-form进行了样本处理,并有了一个想法。对于我的表单,我还使用了具有向导功能的redux表单,它没有保留状态(即使使用destroyOnUnmount: false也是如此)。为了解决这个问题,我删除了向导功能,仅使用一种形式(向导使用多种形式)并隐藏和显示了问题本身。有人告诉我问题出在多种形式不保持状态。代码如下:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { compose, bindActionCreators } from "redux";
import injectReducer from '../../utils/injectReducer';
import injectSaga from '../../utils/injectSaga';
import { SubmissionError } from 'redux-form';
import { Redirect } from "react-router-dom";
import { fetchQuestions } from './actions';
import reducer from './reducer';
import saga from './sagas';
import QuestionForm from './QuestionForm';
import { addAnswer } from './actions';

export class Quiz extends Component {
  constructor(props) {
    super(props)
    this.submitQuiz = this.submitQuiz.bind(this)
    // this.previousPage = this.previousPage.bind(this)
    this.state = {
      page: 1,
      sendToSummary: false,
    }
  }
  componentDidMount(){
    return new Promise((resolve, reject) => {
      this.props.fetchQuestions(resolve, reject);
      this.props.addAnswer();
    }).catch((error) => {
      throw new SubmissionError(error);
    })
  }
  submitQuiz() {
    console.log("sub");
    this.setState(() => ({
      sendToSummary: true
    }))
  }

  render(){
    console.log(this.props, "test");
    const { page } = this.state;
    const { questions } = this.props
    return (
      <div className="quiz-form">
       {questions ? 
          <QuestionForm 
            onSubmit={this.submitQuiz} 
            // previousPage={this.previousPage}
            questions={questions}
          />
         : 'loading'}
        {(this.state.sendToSummary === true) ? <Redirect to='/summary' /> : null}

      </div>
    );
  }
}

function mapSateToProps(state){
  console.log(state)
  return {
    form: state.get('form'),
    questions: state.getIn(['questionSet', 'questions'])
  }
}
const mapDispatchToProps = dispatch => ({
  fetchQuestions: () => dispatch(fetchQuestions()),
  addAnswer: () => dispatch(addAnswer()),
})

const withReducer = injectReducer({key: `questionSet`, reducer});
const withSaga = injectSaga({key: `questionSet`, saga});
const withConnect = connect(
  state => mapSateToProps, mapDispatchToProps
);

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

这是表格:

import React, { Component } from 'react';
import RadioButton from '../../components/RadioButton';
import { Field, reduxForm, SubmissionError } from 'redux-form';
import { Button, Form } from 'reactstrap';
import ReactHtmlParser from 'react-html-parser';
import { addAnswer } from './actions';
import { connect } from 'react-redux';
import Progress from '../../components/Progress';

class QuestionForm extends Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedValues:[],
      isChecked: true,
      currentQuestion: 0
    };
    this.nextPage = this.nextPage.bind(this);
    this.previousPage = this.previousPage.bind(this);

  }
  nextPage(){
    if(this.state.currentQuestion !== this.props.questions-1){
      this.setState({ currentQuestion: this.state.currentQuestion + 1 })
    }
  }
  previousPage(){
    if(this.state.currentQuestion !== 0){
      this.setState({ currentQuestion: this.state.currentQuestion - 1 })
    }
  }
  render(){
    const { handleSubmit, questions } = this.props;
    console.log(this.props.questions)
    return (
      <form onSubmit={handleSubmit} className="quizForm">
        {questions.map((question,i) => {
          console.log(i, this.state.currentQuestion)
          return (
            <div key= {`question-${i}`} className={this.state.currentQuestion === i ? '':'d-none'}>
              <h1>{ question.category }</h1>
              <h2>{ ReactHtmlParser(question.question) }</h2>
              <RadioButton name={`question-${i}`} label="true" radioButtonValue={true} />
              <RadioButton name={`question-${i}`} label="false" radioButtonValue={false} />
              <Button type="button" onClick={this.previousPage} className="next">
                Previous
              </Button>
              {this.state.currentQuestion === questions.length-1 ? <Button type="submit" className="next" onClick={() => this.nextPage(i)}>
                Submit
              </Button>: <Button type="button" className="next" onClick={() => this.nextPage(i)}>
                Next
              </Button>}
            </div>
          )
        })}
      <Progress page={this.state.currentQuestion + 1} total={10}/>
      </form>
    )
  }
}
function mapStateToProps(state){
  console.log(state)
  return {
    form: state.get('form'),
    questions: state.getIn(['questionSet', 'questions'])
  }
}
const mapDispatchToProps = dispatch => ({
  fetchQuestions: () => dispatch(fetchQuestions()),
  addAnswer: () => dispatch(addAnswer()),
})

QuestionForm = connect(state => (mapStateToProps, mapDispatchToProps))(QuestionForm)

export default reduxForm({
  form: 'quiz_form',
  destroyOnUnmount: false,
  // forceUnregisterOnUnmount: true,
  // keepDirtyOnReinitialize: true
})(QuestionForm);