2017-09-15 142 views
0

我試圖映射一個REDX表單的initialValues屬性,以便可以預先填充表單(這是從外部API填充的用戶配置文件編輯屏幕)。map initialValues使用嵌套對象動態支持

由於在API上發生了允許用戶被管理的字段的驗證,因此React JS前端在填充初始值時需要儘可能動態。 I did在SO上發現了另一個問題,它解決了動態預填充initialValuesDynamically load initialValues in Redux Form),但是該解決方案只適用於沒有嵌套的對象。不幸的是,從API 我的反應確實包含一些嵌套:

{ 
    "id": 1, 
    "email": "[email protected]", 
    "location_id": 2, 
    "created_at": "2017-09-08 19:55:01", 
    "updated_at": "2017-09-08 19:55:01", 
    "can_edit": [ // <-- this array contains all the fields that the given user is allowed to edit on the given profile. 
     "profile_img", // <-- possibly this could be rewritten to return for example 'profile.profile_img' rather than just 'profile_img', but not sure how that could help 
     "password" // <-- not returned in the actual user object for obvious reasons, but there is logic for displaying the password field anyway 
    ], 
    "profile": { 
     "user_id": 1, 
     "first_name": "Admin", 
     "last_name": "Test", 
     "profile_img": "https://pbs.twimg.com/profile_images/449750767281254400/M_ukevnA.jpeg", 
     "position": "Admin", 
     "created_at": "2017-09-13 11:38:49", 
     "updated_at": "2017-09-13 11:38:49", 
    }, 
    "location": { 
     "id": 2, 
     "text": "Test Location", 
     "lang": "en", 
     "created_at": "2017-09-13 11:35:41", 
     "updated_at": "2017-09-13 11:35:41", 
     "deleted_at": null 
    } 
} 

所以我不能簡單地直接填充initialValues - 因爲,例如,可以編輯的字段包括email或root用戶對象的location_id,或者嵌套配置文件對象的first_name,last_nameprofile_img屬性。

作爲參考,我的EditProfile組件在下面(截斷到相關部分)。

class EditProfile extends Component { 

    /** 
    * Static property types. 
    */ 
    static propTypes = { 
     ... 
    } 

    /** 
    * Renders editable profile fields. 
    */ 
    profileFields(user) { 
     if(!this.state.currentField.length){ 
      this.state.currentField = user.can_edit[0] 
     } 

     let fields = user.can_edit.map((can_edit) => { 
      switch(can_edit){ 

       // render an email input 
       case 'email': 
        return (
         <ProfileFieldGroup key={can_edit} show={ this.state.currentField == can_edit }> 
          <label htmlFor="email">Email</label> 
          <Field 
           name="email" 
           id="email" 
           type="email" 
           component="input" 
           value={ user.email } 
          /> 
         </ProfileFieldGroup> 
        ) 

       // render a group of password inputs 
       case 'password': 
        return (
         <ProfileFieldGroup key={can_edit} show={ this.state.currentField == can_edit }> 
          <label htmlFor="old_password">Old Password</label> 
          <Field 
           name="old_password" 
           id="old_password" 
           type="password" 
           component="input" 
          /> 

          <label htmlFor="password">New Password</label> 
          <Field 
           name="password" 
           id="password" 
           type="password" 
           component="input" 
          /> 

          <label htmlFor="password_confirm">Confirm New Password</label> 
          <Field 
           name="password_confirm" 
           id="password_confirm" 
           type="password" 
           component="input" 
          /> 
         </ProfileFieldGroup> 
        ) 

       // by default, create a text input whose ID and name match the given property 
       default: 
        console.log(user.profile[can_edit]) 
        return (
         <ProfileFieldGroup key={can_edit} show={ this.state.currentField == can_edit }> 
          <label htmlFor={can_edit}>{ humanizeText(can_edit) }</label> 
          <Field 
           name={ can_edit } 
           id={ can_edit } 
           type="text" 
           component="input" 
           value={ user.profile[can_edit] } 
          /> 
         </ProfileFieldGroup> 
        ) 
      } 
     }) 

     return (
      <div> 
       { fields } 
      </div> 
     ) 
    } 

    /** 
    * Handles the submit event. 
    * This function is mainly managed by Redux. 
    */ 
    submit = (values) => { 
     ... 
    } 

    /** 
    * Renders the component. 
    */ 
    render() { 
     const { 
      handleSubmit, 
      user: user, 
      save: save 
     } = this.props 

     return (
      <section> 
       <header> 
        <h1>Edit User</h1> 
       </header> 

       <div className="main"> 
        <form onSubmit={ handleSubmit(this.submit) }> 

         {user.successful && !user.requesting && 
          this.profileFields(user.user) 
         } 

         {user.requesting && !user.successful && (
          <img className="loader" src=""/> 
         )} 

        </form> 
       </div> 

       <footer> 

       </footer> 
      </section> 
     ) 
    } 
} 

然後連接到終極版:

const mapStateToProps = state => ({ 
    user: state.user, 
    save: state.save, 
    initialValues: state.user.user // <-- this right here 
}) 

const connected = connect(mapStateToProps, { apiGetRequest, 
apiPostRequest })(EditProfile) 

const formed = reduxForm({ 
    form: 'editprofile', 
})(connected) 

總結:我怎麼能動態地從一個潛在的嵌套對象填充終極版形式的initialValues財產?這樣的事情甚至有可能實現嗎?

回答

0

我該如何動態地從潛在的嵌套對象中填充一個redux表單的initialValues屬性?這樣的事情甚至有可能實現嗎?

是的,這是可能的。如果您收到來自API的嵌套數據,根據documentation,可以設置name prop中的keypath:

function Form ({ handleSubmit }) { 
    return (
    <form onSubmit={handleSubmit}> 
     // ... 
     <Field name="my.nested.prop" ... /> 
    </form> 
) 
}