【问题标题】:Redux-Form initial values fromRedux-Form 初始值来自
【发布时间】:2017-05-07 03:04:57
【问题描述】:

我正在尝试使用来自 API 的数据填写个人资料表单。不幸的是 redux-form 在这种情况下不想与我合作。出于某种原因,无论我做什么,字段都是空的。

出于某种原因,设置固定值而不是从 reducer 传递的值效果很好。

也许这是因为我在动作创建者内部使用 redux-promise 进行 API 调用?我怎样才能忍受它并摆脱它。这是我的表单组件。

import React, { Component } from 'react';
import { reduxForm, Field } from 'redux-form';
import { connect } from 'react-redux';
import { fetchRoleList, fetchUserData } from '../actions';

class UserEdit extends Component {

    componentWillMount() {
        this.props.fetchRoleList();
        this.props.fetchUserData();
    }

    handleEditProfileFormSubmit(formProps) {
        console.log(formProps);
    }

    getRoleOptions(selected_id) {
        if (!this.props.profile) {
            return <option>No data</option>;
        }

        return this.props.profile.roles.map(role => {
            return <option key={role.role_id} value={role.role_id}>{role.name}</option>;
        });
    }

    renderField(props) {
        const { input, placeholder, label, value, type, meta: { touched, error } } = props;
        return (
        <fieldset className={`form-group ${ (touched && error) ? 'has-error' : '' }`}>
            <label>{label}</label>
            <input className="form-control" {...input} type={type} placeholder={placeholder} />
            {touched && error && <div className="error">{error}</div>}
        </fieldset>
        );
    }

    renderSelect({ input, placeholder, options, label, type, meta: { touched, error } }) {
        return (
        <fieldset className={`form-group ${ (touched && error) ? 'has-error' : '' }`}>
            <label>{label}</label>
            <select className="form-control" {...input}>
                {options}
            </select>
            {touched && error && <div className="error">{error}</div>}
        </fieldset>
        );
    }

    render() {
        const { handleSubmit } = this.props;

        const user = this.props.profile.user;

        return (
        <div> {user ? user.email : ''}
            <form onSubmit={handleSubmit(this.handleEditProfileFormSubmit.bind(this))}>
                <Field name="email" label="Email:" component={this.renderField} type="text" placeholder="email@gmail.com" className="form-control"/>
                <Field name="name" label="Name:"  component={this.renderField} type="text" placeholder="John Doe" className="form-control"/>
                <Field name="role" label="Role:" component={this.renderSelect} type="select" className="form-control" options={this.getRoleOptions()}/>
                <button action="submit" className="btn btn-primary">Edit user</button>

                <Field name="password" label="Password:" component={this.renderField} type="password" className="form-control"/>
                <Field name="passwordConfirm" label="Confirm Password:" component={this.renderField} type="password" className="form-control"/>
                { this.props.errorMessage
                &&  <div className="alert alert-danger">
                        <strong>Oops!</strong> {this.props.errorMessage}
                    </div> }
                <button action="submit" className="btn btn-primary">Sign up!</button>
            </form>
        </div>
        );
    }

}

let InitializeFromStateForm = reduxForm({
    form: 'initializeFromState'
})(UserEdit);

InitializeFromStateForm = connect(
  state => ({
    profile: state.profile,
    initialValues: state.profile.user
  }),
  { fetchRoleList, fetchUserData }
)(InitializeFromStateForm);

export default InitializeFromStateForm;

我相信动作创建器也会很有用:

export function fetchUserData(user_id) {
    user_id = user_id ? user_id : '';

    const authorization = localStorage.getItem('token');
    const request = axios.get(`${ROOT_URL}/user/${user_id}`, {
      headers: { authorization }
    });

    return {
        type: FETCH_USER,
        payload: request
    };
}

【问题讨论】:

  • 那么问题是尽管您的 initialValues 道具已更改,但您的表单并未填充新数据,对吗?
  • 其实不是。我想最初用减速器的数据填写表格,以后不关心减速器。

标签: reactjs redux react-redux redux-form


【解决方案1】:

您需要添加enableReinitialize: true,如下所示。

let InitializeFromStateForm = reduxForm({
    form: 'initializeFromState',
    enableReinitialize : true // this is needed!!
})(UserEdit)

如果您的 initialValues 属性得到更新,您的表单也会更新。

【讨论】:

  • 花了 3 个小时搜索。很难找到,但enableReinitialize : true 完成了这项工作。谢谢你。
  • 我什至不会承认我今天为此浪费了多少时间。你真是个英雄!
  • 我花了大约三个小时在这上面。谢谢!
  • 哦,伙计,但是那个文档花了几个小时:(
  • 是的。有用。太奇怪了,官方文档里没找到
【解决方案2】:

要设置initialValues,在redux 的connect() 装饰器之前应用reduxForm() 装饰器很重要。如果装饰器的顺序颠倒,则不会从 store 状态填充字段。

const FormDecoratedComponent = reduxForm(...)(Component)
const ConnectedAndFormDecoratedComponent = connect(...)(FormDecoratedComponent)

如果除了第一次设置值之外,您还需要在每次状态更改时重新填充表单,然后设置enableReinitialize: true

this answer中找到一个简单的例子。

阅读官方documentation and full example

阅读此问题here

【讨论】:

    【解决方案3】:

    所以,你正在尝试:

    • 将 API 数据加载到表单中
    • 在加载时更新表单(又名initialValues

    虽然@FurkanO 可能会起作用,但我认为最好的方法是在您获得所有异步数据时加载表单,您可以通过创建父组件/容器来做到这一点:

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

    基本上你应该在UserEditLoader 中做的是执行 API 函数并更新状态(或者如果 redux 连接了 props)。每当 profile 变量不为空(意味着你得到了你期望的数据),然后挂载 UserEdit 并将 profile 作为 prop。

    【讨论】:

      【解决方案4】:

      initialize() 是 reduxForm 提供的一个 prop,可以用来填充表单值。

      change() 是 reduxFrom 提供的另一个用于更改字段值的 prop。

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

      【讨论】:

        【解决方案5】:

        如果 enableReinitialize : true 技巧不起作用,您可以在 initialValues 属性更改时更新每个字段。

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

        我从未与FieldsArray 合作过,但我认为这在这里行不通。

        【讨论】:

          【解决方案6】:

          对于一个无状态的功能组件,你可以这样做:

          componentWillMount() {
            this.props.initialize({ discountCodes: ["ABC200", "XYZ500"] });
          }
          

          对于一个类,你可以这样做:

          const mapStateToProps = state => (
            {
              initialValues: {
                discountCodes: ["ABC200", "XYZ500"]
            }
          );
          

          【讨论】:

            猜你喜欢
            • 2017-10-24
            • 1970-01-01
            • 1970-01-01
            • 2018-05-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-12-25
            相关资源
            最近更新 更多