反应:组件正在更改要控制的文本类型的不受控制的输入

时间:2019-02-04 11:54:10

标签: reactjs

我的组件EditProfile使用了可重用的表单组件ProfileForm,如下所示。

EditProfile

class EditProfile extends Component {
    constructor(props) {
        super(props);

        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
    }

    componentDidMount() {
      this.props.getCurrentProfile();
    }

    onSubmit(profileData) {
      this.props.createProfile(profileData, this.props.history);
    }

    onChange(evt) {
      this.setState({ [evt.target.name]: evt.target.value });
    }

    render() {
      return <ProfileForm profile={this.props.profile} errors={this.props.errors} onSubmit={this.onSubmit} />
    }

    EditProfile.propTypes = {
      profile: PropTypes.object.isRequired,
      errors: PropTypes.object.isRequired,
      createProfile: PropTypes.func.isRequired,
      getCurrentProfile: PropTypes.func.isRequired
    };

    const mapStateToProps = (state) => ({
      profile: state.profile,
      errors: state.errors
    });

    export default connect(mapStateToProps, { createProfile, getCurrentProfile })(withRouter(EditProfile));
}

ProfileForm

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import isEmpty from '../validation/is-empty';
import PropTypes from 'prop-types';
import TextFieldGroup from './common/TextFieldGroup';
import InputGroup from './common/InputGroup';
import SelectListGroup from './common/SelectListGroup';
import TextAreaFieldGroup from './common/TextAreaFieldGroup';

class ProfileForm extends Component {
    constructor(props) {
        super(props);

        this.state = {
            displaySocialInputs: false,
            handle: props.profile ? props.profile.handle : '',
            company: props.profile ? props.profile.company : '',
            website: props.profile ? props.profile.website : '',
            location: props.profile ? props.profile.location : '',
            status: props.profile ? props.profile.status : '',
            skills: props.profile ? props.profile.skills : '',
            githubusername: props.profile ? props.profile.githubusername : '',
            bio: props.profile ? props.profile.bio : '',
            twitter: props.profile ? props.profile.twitter : '',
            facebook: props.profile ? props.profile.facebook : '',
            linkedin: props.profile ? props.profile.linkedin : '',
            youtube: props.profile ? props.profile.youtube : '',
            instagram: props.profile ? props.profile.instagram : '',
            errors: props.errors || {}
        };

        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.errors) {
            this.setState({ errors: nextProps.errors });
        }

        if (nextProps.profile.profile) {
            const profile = nextProps.profile.profile;

            // bring skills array back to csv
            const skillsCsv = profile.skills.join(',');

            // if profile field wasn't provided set it to an empty string
            profile.company = !isEmpty(profile.company) ? profile.company : '';
            profile.website = !isEmpty(profile.website) ? profile.website : '';
            profile.location = !isEmpty(profile.location) ? profile.location : '';
            profile.githubusername = !isEmpty(profile.githubusername) ? profile.githubusername : '';
            profile.bio = !isEmpty(profile.bio) ? profile.bio : '';
            profile.social = !isEmpty(profile.social) ? profile.social : {};
            profile.twitter = !isEmpty(profile.social.twitter) ? profile.social.twitter : '';
            profile.facebook = !isEmpty(profile.social.facebook) ? profile.social.facebook : '';
            profile.linkedin = !isEmpty(profile.social.linkedin) ? profile.social.linkedin : '';
            profile.youtube = !isEmpty(profile.social.youtube) ? profile.social.youtube : '';
            profile.instagram = !isEmpty(profile.social.instagram) ? profile.social.instagram : '';

            // set component state
            this.setState({
                handle: profile.handle,
                company: profile.company,
                website: profile.website,
                location: profile.location,
                status: profile.status,
                skills: skillsCsv,
                githubusername: profile.githubusername,
                bio: profile.bio,
                twitter: profile.twitter,
                facebook: profile.facebook,
                linkedin: profile.linkedin,
                youtube: profile.youtube,
                instagram: profile.instagram
            });
        }
    }

    onChange(evt) {
        this.setState({ [evt.target.name]: evt.target.value });
    }

    onSubmit(evt) {
        evt.preventDefault();

        const profileData = {
            handle: this.state.handle,
            company: this.state.company,
            website: this.state.website,
            location: this.state.location,
            status: this.state.status,
            skills: this.state.skills,
            githubusername: this.state.githubusername,
            bio: this.state.bio,
            twitter: this.state.twitter,
            facebook: this.state.facebook,
            linkedin: this.state.linkedin,
            youtube: this.state.youtube,
            instagram: this.state.instagram
        }

        this.props.onSubmit(profileData);
    }

    render() {
        const { errors, displaySocialInputs } = this.state;

        let socialInputs;
        if (displaySocialInputs) {
            socialInputs = (
                <div>
                    <InputGroup
                        placeholder="Twitter profile URL"
                        name="twitter"
                        icon="fab fa-twitter"
                        value={this.state.twitter}
                        onChange={this.onChange}
                        error={errors.twitter}
                    />
                    <InputGroup
                        placeholder="Facebook profile URL"
                        name="facebook"
                        icon="fab fa-facebook"
                        value={this.state.facebook}
                        onChange={this.onChange}
                        error={errors.facebook}
                    />
                    <InputGroup
                        placeholder="LinkedIn profile URL"
                        name="linkedin"
                        icon="fab fa-linkedin"
                        value={this.state.linkedin}
                        onChange={this.onChange}
                        error={errors.linkedin}
                    />
                    <InputGroup
                        placeholder="YouTube channel URL"
                        name="youtube"
                        icon="fab fa-youtube"
                        value={this.state.youtube}
                        onChange={this.onChange}
                        error={errors.youtube}
                    />
                    <InputGroup
                        placeholder="Instagram page URL"
                        name="instagram"
                        icon="fab fa-instagram"
                        value={this.state.instagram}
                        onChange={this.onChange}
                        error={errors.instagram}
                    />
                </div>
            )
        }

        // select options for status
        const options = [
            { label: '* Select professional status', value: '', disabled: 'disabled'},
            { label: 'developer', value: 'developer' },
            { label: 'senior developer', value: 'senior developer' },
            { label: 'manager', value: 'manager' },
            { label: 'student or learning', value: 'student or learning' },
            { label: 'instructor or teacher', value: 'instructor or teacher' },
            { label: 'intern', value: 'intern' },
            { label: 'other', value: 'other' }
        ];

        return (
            <div className="create-profile">
                <div className="container">
                    <div className="row">
                        <div className="col-md-8 m-auto">
                            {this.state.handle && <Link to="/dashboard" className="btn btn-light">Go to dashboard</Link>}
                            <h1 className="display-4 text-center">Edit your profile</h1>
                            {!this.state.handle && <p className="lead text-center">Lets get some information to make your profile stand out</p>}
                            <small className="d-block pb-3">* = required fields</small>
                            <form onSubmit={this.onSubmit}>
                                <TextFieldGroup
                                    placeholder="* Profile Handle"
                                    name="handle"
                                    value={this.state.handle}
                                    onChange={this.onChange}
                                    error={errors.handle}
                                    info="A unique handle for your profile URL. Your full name, company name, nickname, etc."
                                />
                                <SelectListGroup
                                    placeholder="Status"
                                    name="status"
                                    value={this.state.status}
                                    onChange={this.onChange}
                                    options={options}
                                    error={errors.status}
                                    info="Give us an idea where you are at in your career"
                                />
                                <TextFieldGroup
                                    placeholder="Company"
                                    name="company"
                                    value={this.state.company}
                                    onChange={this.onChange}
                                    error={errors.company}
                                    info="Could be your own company or one you work for"
                                />
                                <TextFieldGroup
                                    placeholder="Website"
                                    name="website"
                                    value={this.state.website}
                                    onChange={this.onChange}
                                    error={errors.website}
                                    info="Could be your own website or a company one"
                                />
                                <TextFieldGroup
                                    placeholder="Location"
                                    name="location"
                                    value={this.state.location}
                                    onChange={this.onChange}
                                    error={errors.location}
                                    info="City or city & state suggested (e.g. Boston, MA)"
                                />
                                <TextFieldGroup
                                    placeholder="Skills"
                                    name="skills"
                                    value={this.state.skills}
                                    onChange={this.onChange}
                                    error={errors.skills}
                                    info="Please use comma separated values (e.g. HTML, CSS, JS, PHP)"
                                />
                                <TextFieldGroup
                                    placeholder="Github username"
                                    name="githubusername"
                                    value={this.state.githubusername}
                                    onChange={this.onChange}
                                    error={errors.githubusername}
                                    info="If you want your latest repos and a Github link, include your username"
                                />
                                <TextAreaFieldGroup
                                    placeholder="Short bio"
                                    name="bio"
                                    value={this.state.bio}
                                    onChange={this.onChange}
                                    error={errors.bio}
                                    info="Tell us a little about yourself"
                                />
                                <div className="mb-3">
                                    <button type="button"
                                        onClick={() => this.setState((prevState) => ({ displaySocialInputs: !prevState.displaySocialInputs }))}
                                        className="btn btn-light">Add social network links
                                    </button>
                                    <span className="text-muted">Optional</span>
                                </div>
                                {socialInputs}
                                <input type="submit" value="Submit" className="btn btn-info btn-block mt-4" />
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

ProfileForm.propTypes = {
    profile: PropTypes.object.isRequired,
    errors: PropTypes.object.isRequired
};

export default ProfileForm;

我相信value构造函数中TextFieldGroupSelectListGroupTextAreaFieldGroup的{​​{1}}字段将被设置为'',但会收到警告类似于

ProfileForm

,其他输入组件也使用相同的警告。最终得到这个

Failed prop type: The prop `value` is marked as required in `TextAreaFieldGroup`, but its value is `undefined`.

我在哪里错了?

2 个答案:

答案 0 :(得分:0)

您在EditProfile中获得的道具未在

中声明
  this.state = {

        }
父组件的

React - changing an uncontrolled input之前已经回答了这个问题。

查看您的父组件。当您未设置对象的状态并将其用作 input select 标记中的值时,将显示此错误。

答案 1 :(得分:0)

原因可能是TextFieldGroup,而其他类似组件在value={this.state.<prop_name>}构造函数参与设置ProfileForm上的状态之前,已用ProfileForm进行了初始化。 仅在页面刷新上加载EditProfile组件时才会发生该错误。如果我来自带有用户个人资料的页面,则没有错误。