javascript - 收到错误bundle.js :39454 Uncaught TypeError: Cannot read property 'email' of undefined using MERN stack

标签 javascript node.js mongodb reactjs

我正在使用 MERN 堆栈,但似乎无法弄清楚为什么会发生这种情况。我有一个显示得很好的帖子列表。当我单击帖子时,我在控制台内收到 Cannot read property 'email' undefined 。但是,如果我点击刷新,一切都会正常工作,并且该帖子会显示所有工作问题。

我能够查明我的 renderComments() 函数的错误。这就是所有内容都显示为未定义的地方。

编辑:我想我发现发生了什么,但我不确定为什么会发生。在渲染发生之前,在 array.map 函数中创建的注释只是注释 ID。仅当组件呈现时,注释才是具有其所有属性的实际完整对象。我将发布后端来展示我如何获取帖子上的评论以提供帮助。

要求在 array.map 函数之前显示 post 的 console.log。由于这确实指出了我在编辑中所说的内容,因此我将继续并在下面显示以提供帮助。

enter image description here

发布带有评论的 Controller :

exports.getOnePost = function(req, res, next) {
  Posts.findById(req.params.id).populate("comments").exec(function(err, foundPost) {
    if(err) {
      return next(err);
    } else {
      res.json(foundPost);
    }
  });
}

发帖和评论模型:

var mongoose = require("mongoose");
const Schema = mongoose.Schema;

var postsSchema = new Schema({
    title: String,
    createdAt: {type: Date, default: Date.now},
    content: String,
    author: {
        id: {
            type: mongoose.Schema.Types.ObjectId,
            ref: "user"
        },
        email: String
    },
    comments: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: "comments"
        }
    ]
});

var Posts = mongoose.model("posts", postsSchema);

module.exports = Posts;
<小时/>
var mongoose = require("mongoose");
const Schema = mongoose.Schema;

var commentSchema = new Schema({
    text: String,
    createdAt: {type: Date, default: Date.now },
    author: {
        id: {
            type: mongoose.Schema.Types.ObjectId,
            ref: "User"
        },
        email: String
    }
});

module.exports = mongoose.model("comments", commentSchema);

Post_show页面:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { bindActionCreators } from 'redux';
import * as actions from '../../actions/posts_actions';
import * as actionsIndex from '../../actions/index';
import * as actionsComments from '../../actions/comments_actions';

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

    this.onDeleteClick = this.onDeleteClick.bind(this);
    this.deleteComment = this.deleteComment.bind(this);
  }

  componentDidMount() {
    const {id} = this.props.match.params;
    this.props.getOnePost(id);

    if(this.props.auth) {
      this.props.getUser();
    }
  }

  renderButtons() {
    const { post } = this.props;

    if(!this.props.user) {
      return ( <div></div> );
    }

    if(this.props.auth) {
      if(this.props.user._id === post.author.id) {
        return (
          <div>
            <button
              onClick={this.onDeleteClick}
              className="btn btn-danger"
              >
              Delete
            </button>
            <Link
              to={`/posts/${post._id}/edit`}
              className="btn btn-success"
              >
              Edit
            </Link>
          </div>
        )
      }
    } else {
      return (
        <div></div>
      )
    }
  }

  renderCommentsButtons(comment) {
    const { post, user, auth } = this.props;

    if(!user) {
      return (<div></div>);
    }

    if(auth) {
      if(user._id === comment.author.id) {
        return (
          <div>
            <button
              onClick={() => this.deleteComment(comment)}
              className="btn btn-xs btn-danger">
              Delete
            </button>
            <Link
              to={`/posts/${post._id}/comments/${comment._id}/edit`}
              className="btn btn-xs btn-warning">
              Edit
            </Link>
          </div>
        )
      }
    }
  }

  renderComments() {
    const { post } = this.props;

    return post.comments.map((comment) => {
      return (
        <li className="list-group-item" key={comment._id}>
          <div>
            {comment.text} : {comment.author.email}
          </div>
          {this.renderCommentsButtons(comment)}
        </li>
      );
    });
  }

  deleteComment(comment) {
    const {id} = this.props.match.params;
    const {user, post, auth} = this.props;

    if(!user) {
      return (<div></div>);
    }

    if(auth) {
      if(user._id === comment.author.id){
        console.log(comment._id, '-', post._id);
        // this.props.deleteComments(id, comment._id, () => {
        //   this.props.history.push(`/posts/${post._id}`);
        // });
      }
    }
  }

  onDeleteClick() {
    const {id} = this.props.match.params;

    if(!this.props.user) {
      return (<div></div>);
    }

    if(this.props.auth) {
      if(this.props.user._id === this.props.post.author.id) {
        this.props.deletePost(id, () => {
          this.props.history.push("/posts");
        });
      }
    }
  }

  render() {
    const { post } = this.props;

    if (!post) {
      return <div> Loading...No Post</div>;
    }

    return (
      <div>
        <Link className="btn btn-primary" to="/posts">Back To Post</Link>
        <h3>{post.title}</h3>
        <p>{post.content}</p>
        <p>created by: {post.author.email}</p>
        <ul className="list-group">
          {this.renderComments()}
        </ul>
        {this.renderButtons()}
        <Link
          className="btn btn-warning"
          to={`/posts/${post._id}/comments/new`}>
            Comment
        </Link>
      </div>
    );
  }
}

function mapStateToProps({ posts, auth, user }, ownProps) {
  return {
    post: posts[ownProps.match.params.id],
    user: user,
    auth: auth.authenticated
  };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({...actions, ...actionsIndex, ...actionsComments}, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(ShowPosts);

发布

import React , { Component } from 'react';
import * as actions from '../../actions/posts_actions';
import {connect} from 'react-redux';
import {Link} from 'react-router-dom';
import _ from 'lodash';


class Posts extends Component {
  componentDidMount() {
    this.props.getAllPosts();
  }

  renderPosts() {
    return _.map(this.props.posts, post => {
      return (
        <Link to={`/posts/${post._id}`} key={post._id}>
          <li className="list-group-item">
            {post.title}
          </li>
        </Link>
      )
    });
  }

  render() {
    return (
      <div>
        <div className="text-xs-right">
          <Link className="btn btn-primary" to="/posts/new">
            Add a Post
          </Link>
        </div>
        <h3>Posts</h3>
        <ul className="list-group">
          {this.renderPosts()}
        </ul>
      </div>
    );
  }
}


function mapStateToProps(state) {
  return {
    posts: state.posts
  };
}

export default connect(mapStateToProps, actions)(Posts);

最佳答案

这是一个后端问题。正如编辑中所述,首先呈现的帖子只有评论的评论 ID,而不是完整的评论对象。我相信发生的事情是,最初的帖子来自 posts[ownProps.match.params.id] ,它所做的就是从客户端的帖子中获取单个帖子。

如果您查看后端,我会将评论存储为 objectID,然后在调用 getOnePost 时填充它们。

我需要做的是在所有帖子被调用之前填充评论,这样评论就已经填充了,而不仅仅是 ID。因此,为了解决这个问题,我执行了以下操作(我还将发布所需的所有其他代码)。

导出到后端路由器的函数:

旧:

exports.getAllPosts = function(req, res, next) {
  Posts.find({}, function(err, posts) {
    if(err) {
      return next(err);
    } else {
      res.json(posts);
    }
  });
}

新:

exports.getAllPosts = function(req, res, next) {
  Posts.find({}).populate("comments").exec(function(err, posts) {
    if(err) {
      return next(err);
    } else {
      res.json(posts);
    }
  });
}

这是帖子模型:

var mongoose = require("mongoose");
const Schema = mongoose.Schema;

var postsSchema = new Schema({
    title: String,
    createdAt: {type: Date, default: Date.now},
    content: String,
    author: {
        id: {
            type: mongoose.Schema.Types.ObjectId,
            ref: "user"
        },
        email: String
    },
    comments: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: "comments"
        }
    ]
});

var Posts = mongoose.model("posts", postsSchema);

module.exports = Posts;

这两个模型已在上面发布。

关于javascript - 收到错误bundle.js :39454 Uncaught TypeError: Cannot read property 'email' of undefined using MERN stack,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44909013/

相关文章:

node.js - 等待nodejs异步任务完成

c# - MongoDb SafeMode 与 WriteConcern 的比较

javascript - 如何关闭使用 ":target"伪类创建的绝对定位窗口?

javascript - 从数组中删除最小值,但如果重复只删除一次

javascript - Crossfilter/d3.js - 我可以显示通过交叉过滤器选择的记录的分数吗?

mysql - 如何在插入数据之前检查nodejs中的mysql表字段类型

node.js - 错误:没有匹配的函数可用于调用‘v8::Object::Set(v8::Local<v8::String>

java - MongoDB:使用 or 语句查询

node.js - 带 Node 驱动程序的 Mongo 游标

javascript - 谷歌地图信息窗口中的 Angular