“user.profile” 未定义,尽管它在 Accounts.createUser() 中声明

"user.profile" undefined despite its declaration in Accounts.createUser()

本文关键字:createUser Accounts 声明 profile user 未定义      更新时间:2023-09-26

我正在处理一个"设置"页面,登录用户可以在其中更改他们的个人资料图片。然而,流星似乎很难找到userprofile属性。

注册.js(这是我在注册时创建用户并创建配置文件属性的地方)

import React, { Component } from 'react';
import { browserHistory } from 'react-router';
export default class Signup extends Component {
  handleSubmit(event) {
    event.preventDefault();
    var signupEmail = event.target.signupEmail.value;
    var signupPassword = event.target.signupPassword.value;
    if (signupPassword !== '') {
      Accounts.createUser({
        email: signupEmail,
        password: signupPassword,
        profile: {
          avatar: "/user-default.svg"
        }
      }, (err) => {
        err ? (console.log(err.reason)) : browserHistory.push("/app/profile");
      });
    }
  }
  render() {
    return (
      <div className="login-form">
        <form onSubmit={this.handleSubmit}>
          <div className="input-options">
            <input type="text" placeholder="Email" name="signupEmail" />
          </div>
          <div className="input-options">
            <input type="password" placeholder="Password" name="signupPassword" />
          </div>
          <button className="login-submit bold">Sign me up!</button>
        </form>
      </div>
    );
  }
}

profile_settings.js

import React, { Component } from 'react';
import { Link } from 'react-router';
import reactMixin from 'react-mixin';
import ReactMeteorData from 'meteor/react-meteor-data';
export default class ProfileSettings extends Component {
  constructor(props) {
    super(props);
    this.state = {
      avatar: this.props.user.profile.avatar
    }
  }
  getMeteorData(){
    return{
      user: Meteor.user()
    }
  }
  componentWillMount(){
    // we create this rule both on client and server
    Slingshot.fileRestrictions("avatar", {
      allowedFileTypes: ["image/png", "image/jpeg", "image/gif"],
      maxSize: 2 * 500 * 500
    });
  }
  upload(){
    var userId = Meteor.user()._id;
    var metaContext = {avatarId: userId};
    var uploader = new Slingshot.Upload("UsersAvatar", metaContext);
    uploader.send(document.getElementById('input').files[0], function (error, downloadUrl) { // you can use refs if you like
      if (error) {
        // Log service detailed response
        console.error('Error uploading', uploader.xhr.response);
        alert (error); // you may want to fancy this up when you're ready instead of a popup.
      }
      else {
        // we use $set because the user can change their avatar so it overwrites the url :)
        Meteor.users.update(Meteor.userId(), {$set: {"profile.avatar": downloadUrl}}); 
      }
      // you will need this in the event the user hit the update button because it will remove the avatar url
      this.setState({avatar: downloadUrl});
    }.bind(this));
  }
  formSubmit(){
    let avatarUrl = this.state.avatar;
    Meteor.users.update( {_id: Meteor.userId() }, {
      $set: {profile: avatarUrl}
    });
  }
  render() {
    return (
      <div>
        <div className="sticky-header">
          <h3>Settings</h3>
        </div>
        <form>
          <div className="row well">
           <div className="col-md-6">
              <div className="form-group">
                <label htmlFor="exampleInputFile">File input</label>
                <input type="file" id="input" onChange={this.upload.bind(this)} />
                <p className="help-block">Image max restriction: 2MB, 500x500. Cropped: 200x200</p>
              </div>
            </div>
            <div className="col-md-6 utar-r"> 
              <img src={this.state.avatar} height="200" width="200" alt="..." className="img-rounded" />
            </div>
            <div className="form-group">
              <button className="btn btn-lg btn-primary btn-block" type="submit" onClick={this.formSubmit.bind(this)}>Update Profile</button>
            </div>
          </div>
        </form>
        <footer className="sticky-footer">
          <Link to="/app/profile">
            <button className="profile-edit bg-black">
                <h3>Cancel</h3>
            </button>
          </Link>
          <Link to="">
            <button className="profile-edit">
                <h3>Save Changes</h3>
            </button>
          </Link>
        </footer>
      </div>
    );
  }
} 
reactMixin(ProfileSettings.prototype, ReactMeteorData);

这是我得到的错误:TypeError: Cannot read property 'profile' of undefined

错误不是找不到profile属性,而是说没有user(或者user未定义)这正是TypeError: Cannot read property 'profile' of undefined的意思。

代码中存在一些错误:

  • getMeteorData的退货可在this.data下使用,而不是this.props
  • getMeteorData将在constructor之后运行,因此无法在构造函数中获取 Meteor 的数据
  • getMeteorData 以反应方式返回数据,并且在实例化类时可能没有所需的数据

所以我建议使用容器/组件方法,如下所示:

export default class ProfileSettingsContainer extends Component {
  getMeteorData(){
    return{
      user: Meteor.user()
    }
  }
  render() {
    const user = this.data.user;
    if (user) {
      return <ProfileSettings user={user} />
    } else {
      return null; // or what ever placeholder you want while the data is being loaded
    }
  }
}

class ProfileSettings extends Component {
  constructor(props) {
    super(props);
    this.state = {
      avatar: props.user.profile.avatar
    }
  }
}

使用此结构,ProfileSettings将使用以下内容进行实例化props.user

芬纳利,

Meteor.users.update( {_id: Meteor.userId() }, {
  $set: {profile: avatarUrl}
});

应该是

Meteor.users.update( {_id: Meteor.userId() }, {
  $set: {'profile.avatar': avatarUrl}
});

但这无关紧要