【问题标题】:map initialValues prop dynamically with nested objects使用嵌套对象动态映射 initialValues 道具
【发布时间】:2017-09-15 16:49:42
【问题描述】:

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

因为允许用户管理哪些字段的验证发生在 API 上,所以 React JS 前端在填充初始值时需要尽可能动态。我确实在这里找到了另一个关于动态预填充initialValues(Dynamically 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 - 例如,可能的可编辑字段包括根用户对象的emaillocation_id,或first_namelast_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 属性?这样的事情实际上可能吗?

【问题讨论】:

    标签: reactjs redux-form


    【解决方案1】:

    如何从可能嵌套的对象中动态填充 redux 表单的 initialValues 属性?这样的事情实际上可能吗?

    是的,这是可能的。如果你从你的 API 接收嵌套数据,根据documentation,你可以在name prop 中设置keypath:

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

    【讨论】:

      猜你喜欢
      • 2013-02-02
      • 2019-07-26
      • 1970-01-01
      • 1970-01-01
      • 2014-12-30
      • 2016-10-14
      • 1970-01-01
      • 1970-01-01
      • 2020-09-27
      相关资源
      最近更新 更多