Redux-Form 初始值来自

Posted

技术标签:

【中文标题】Redux-Form 初始值来自【英文标题】:Redux-Form initial values from 【发布时间】: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 道具已更改,但您的表单并未填充新数据,对吗? 其实不是。我想最初用减速器的数据填写表格,以后不关心减速器。 【参考方案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"]
  
);

【讨论】:

以上是关于Redux-Form 初始值来自的主要内容,如果未能解决你的问题,请参考以下文章

如何以 redux 形式重置初始值

如何以 redux 形式使用初始化

如何清除表单中的某些字段 - Redux-Form

使用material-ui为redux-form设置initialValues无效

C ++如果值来自成员变量,则复制 初始化和const引用初始化之间存在差异

当钩子的初始值是来自数据库的查询结果时,“比上一次渲染期间渲染的钩子更多”错误