2017-09-15 22 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> 
) 
}