在 Redux 将 Redux State 映射到 Props 后设置组件状态

Posted

技术标签:

【中文标题】在 Redux 将 Redux State 映射到 Props 后设置组件状态【英文标题】:Setting Component State after Redux has Mapped Redux State to Props 【发布时间】:2018-10-25 21:32:42 【问题描述】:

我正在尝试通过从我的组件状态中提取信息来使用 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));

【问题讨论】:

使用更简单的示例可能会更好。 【参考方案1】:

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

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

【讨论】:

以上是关于在 Redux 将 Redux State 映射到 Props 后设置组件状态的主要内容,如果未能解决你的问题,请参考以下文章

redux/react 应用程序中的 state 有一个带有 reducer 名称的属性

防止将重复的对象添加到 state react redux

如何使用react-redux将redux商店中封装的ui状态映射到道具?

将 props 从 redux 映射到组件状态

React / Redux:mapStateToProps 实际上并未将状态映射到道具

React / Redux 主题:基于 Store State 的条件渲染