使用嵌套对象动态映射initialValues prop

时间:2017-09-15 16:49:42

标签: reactjs redux-form

我试图映射一个redux-form的initialValues属性,以便可以预先填充表单(这是一个从外部API填充的用户配置文件编辑屏幕)

由于验证了允许用户管理哪些字段,因此在填充初始值时,React JS前端需要尽可能动态。我上找到了另一个关于动态预填充initialValuesDynamically load initialValues in Redux Form)的问题,但该解决方案仅适用于没有嵌套的对象。不幸的是,我对API 的回复包含了一些嵌套:

{
    "id": 1,
    "email": "admin@test.com",
    "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 - 例如,可能的可编辑字段包括root用户对象的emaillocation_idfirst_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>
        )
    }
}

然后连接到redux:

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)

总结:如何从潜在的嵌套对象动态填充redux表单的initialValues属性?这样的事情几乎可能吗?

1 个答案:

答案 0 :(得分:0)

  

如何从潜在的嵌套对象动态填充redux表单的initialValues属性?这样的事情几乎可能吗?

是的,这是可能的。如果您从API接收嵌套数据,根据documentation,您可以在name道具中设置关键路径:

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