首页 > 解决方案 > 在 Redux 将 Redux State 映射到 Props 后设置组件状态

问题描述

我正在尝试通过从我的组件状态中提取信息来使用 Redux Forms 使用一些用户信息来初始化表单。我的组件的 componentDidMount 方法中有一个 redux 操作,它调用该操作、检索信息,然后将我的商店中的“配置文件”对象映射到组件道具。问题是,当我去 setState 更新配置文件信息时,它返回为未定义。我尝试使用 componentWillRecieveProps 来查看是否可以捕获更新的“配置文件”道具,但它仍然未定义。一旦“this.props.profile”返回用户信息,更新组件状态的最佳方法是什么?

这是组件的代码:

import React, { Component } from "react";
import { connect } from "react-redux";
import { Field, reduxForm } from "redux-form";
import { Link } from "react-router-dom";
import classnames from "classnames";
import * as actions from "../../actions";

class CreateProfile extends Component {
  constructor(props) {
    super(props);
    this.state = {
      showSocialMedia: true,
      profile: {}
    };
  }

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

  // componentDidUpdate(prevProps, prevState) {
  //   if (prevProps.profile.profile !== this.props.profile.profile) {
  //     console.log(this.props.profile);
  //   }
  // }

  renderField(field) {
    return (
      <div className="form-group">
        <input
          className={classnames("form-control form-control-lg", {
            "is-invalid": field.meta.touched && !field.meta.valid
          })}
          type={field.type}
          placeholder={field.placeholder}
          {...field.input}
        />
        <small className="text-muted">{field.description}</small>
        <div className="invalid">
          {field.meta.touched && !field.meta.valid ? (
            <div className="text-center">
              <i className="far fa-edit" /> {field.meta.error}
            </div>
          ) : (
            ""
          )}
        </div>
      </div>
    );
  }

  renderAlert() {
    if (this.props.errors.message) {
      return (
        <div className="alert alert-danger error-message mt-4 text-center">
          <h3>
            <i className="fas fa-info-circle" />
          </h3>
          <h6 className="invalid">{this.props.errors.message}</h6>
        </div>
      );
    }
  }

  renderSelectField(field) {
    return (
      <div className="form-group">
        <select
          className={classnames("form-control form-control-lg", {
            "is-invalid": field.meta.touched && !field.meta.valid
          })}
          {...field.input}
        >
          <option value="" disabled>
            * Select a Professional Status
          </option>
          <option value="Developer">Developer</option>
          <option value="Junior Developer">Junior Developer</option>
          <option value="Senior Developer">Senior Developer</option>
          <option value="Manager">Manager</option>
          <option value="Student or Learning">Student or Learning</option>
          <option value="Instructor or Teacher">Instructor or Teacher</option>
          <option value="Intern">Intern</option>
          <option value="Other">Other</option>
        </select>
        <small className="text-muted">
          Give us an idea of where you are at in your career
        </small>
        <div className="invalid">
          {field.meta.touched && !field.meta.valid ? (
            <div className="text-center">
              <i className="far fa-edit" /> {field.meta.error}
            </div>
          ) : (
            ""
          )}
        </div>
      </div>
    );
  }

  renderSocialMediaField(field) {
    return (
      <div className="form-group">
        <div className="input-group-prepend">
          <span className="input-group-text">
            <i className={field.icon} />
          </span>
          <input
            type={field.type}
            className="form-control"
            placeholder={field.placeholder}
            icon={field.icon}
            {...field.input}
          />
        </div>
      </div>
    );
  }

  onSubmit(values) {
    this.props.createNewUserProfile(values);
  }

  toggleHiddenSocialInputs(e) {
    e.preventDefault();
    this.setState({
      showSocialMedia: !this.state.showSocialMedia
    });
  }
  render() {
    const { handleSubmit } = this.props;
    const { profile } = this.props;
    return (
      <div className="container">
        <div className="row">
          <div className="col-md-8 m-auto">
            <Link to="/dashboard" className="btn btn-light p-2 mt-2">
              <i className="mr-1 fas fa-long-arrow-alt-left" /> Go Back
            </Link>
            <h5 className="display-4 pt-2 text-center font-weight-light">
              Update Your Profile
            </h5>
            <p className="text-black-50 pt-3 font-weight-light">
              * = required field
            </p>
            <form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
              {this.renderAlert()}
              <Field
                name="handle"
                type="text"
                placeholder="* Profile handle"
                component={this.renderField}
                description="A unique handle for your profile URL - (Can't be changed later)"
              />
              <Field name="status" component={this.renderSelectField} />
              <Field
                name="company"
                type="text"
                placeholder="Company"
                component={this.renderField}
                description="Can be your own or the one you work for"
              />
              <Field
                name="website"
                type="text"
                placeholder="Website"
                component={this.renderField}
                description="Could be your own or company website"
              />
              <Field
                name="location"
                type="text"
                placeholder="Location"
                component={this.renderField}
                description="Suggested format is: City, State"
              />
              <Field
                name="skills"
                type="text"
                placeholder=" Skills"
                component={this.renderField}
                description="Please use comma separated values (eg: HTML, CSS, Javascript, etc)"
              />
              <Field
                name="githubusername"
                type="text"
                placeholder="Github Username"
                component={this.renderField}
                description="If you want your latest repos and a Github link, include your username"
              />
              <div className="form-control-group">
                <Field
                  className="form-control form-control-lg"
                  name="bio"
                  placeholder="A short bio about yourself"
                  component="textarea"
                />
                <small className="text-muted">
                  Tell us a little about yourself
                </small>
              </div>
              <div className="row mt-2 pt-2">
                <button
                  className="btn btn-outline-secondary m-auto"
                  onClick={this.toggleHiddenSocialInputs.bind(this)}
                >
                  Add Social Network Links <i className=" ml-1 fas fa-users" />
                </button>
              </div>

              {!this.state.showSocialMedia && (
                <div className="mt-3">
                  <Field
                    name="facebook"
                    placeholder="Facebook profile URL"
                    icon="fab fa-facebook-square"
                    component={this.renderSocialMediaField}
                  />
                  <Field
                    name="twitter"
                    placeholder="Twitter profile URL"
                    icon="fab fa-twitter-square"
                    component={this.renderSocialMediaField}
                  />
                  <Field
                    name="linkedin"
                    placeholder="Linkedin profile URL"
                    icon="fab fa-linkedin"
                    component={this.renderSocialMediaField}
                  />
                  <Field
                    name="youtube"
                    placeholder="Youtube profile URL"
                    icon="fab fa-youtube-square"
                    component={this.renderSocialMediaField}
                  />
                  <Field
                    name="instagram"
                    placeholder="Instagram profile URL"
                    icon="fab fa-instagram"
                    component={this.renderSocialMediaField}
                  />
                </div>
              )}

              <button action="submit" className="btn btn-info btn-block mt-5">
                Create Profile <i className=" ml-1 fas fa-user-alt" />
              </button>
              {this.renderAlert()}
            </form>
          </div>
        </div>
      </div>
    );
  }
}

function validate(values) {
  const errors = {};
  if (!values.handle) {
    errors.handle = "Please enter a handle for your profile";
  }
  if (!values.status) {
    errors.status = "Please select a status for your profile";
  }
  return errors;
}

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

export default reduxForm({
  validate,
  form: "CreateProfile",
  initialValues: {}
})(connect(mapStateToProps, actions)(CreateProfile));

标签: javascriptreactjsreduxreact-reduxredux-form

解决方案


首先,我不确定为什么要将配置文件附加到组件状态。但是,如果 this.props.profile 始终未定义,那么听起来您无法获取用户配置文件或者您没有正确更新商店。我需要查看 getCurrentUserProfile 和您的减速器。

Fwiw,我会从一个容器发送一个对用户信息的请求,并将 initialValues 设置为 state.profile(如果 state.profile 实际上是您的初始用户数据)。


推荐阅读