2016-12-21 49 views
18

我試圖用API中的數據填充配置文件表單。不幸的是,redux-form在這種情況下不想與我合作。無論我做什麼,由於某些原因,字段保持空白Redux-Form初始值從

設置固定值,而不是從減速傳遞工作以及由於某種原因值。

也許這是因爲我正在使用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 protected]" 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 
    }; 
} 
+0

因此,雖然您的initialValues道具得到了改變,但您的表單沒有被填充新的數據嗎? – FurkanO

+0

好吧,不是真的。我想最初填寫減速器的數據,稍後不關心減速器。 – J33nn

回答

46

您需要添加enableReinitialize:真如下。

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

如果您的initialValues道具得到更新,您的窗體也會更新。

+1

是的!就是這個!謝謝你幫了我很多! – J33nn

+5

花了3小時搜索。很難找到,但'enableReinitialize:true'完成了這項工作。感謝那。 –

+2

我甚至不會承認今天我浪費時間與此戰鬥的時間。你確定是英雄! – Ominus

2

所以,你想:

  • 加載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函數和更新狀態(或者終極版連接道具)。只要配置文件變量不爲空(意味着您獲得了您期望的數據),然後將配置文件掛載爲UserEdit

0

如果enableReinitialize : true技巧不起作用,您可以在initialValues prop更改時更新每個字段。

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的工作,但我認爲這不會在這裏工作。

1

要設置initialValues前從終極版的connect()裝飾應用reduxForm()裝飾是很重要的。如果裝飾器的順序顛倒,這些字段將不會從商店狀態填充。

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

如果,除了首次設置的值,則需要每次狀態變化然後設置enableReinitialize: true

查找this answer一個簡單的例子重新填充表單。

閱讀官方documentation and full example

閱讀關於此問題here