Today we will working on the comment feature of CoderBook
Our posts and comments are closely related. A post can have many comments, and a comment must belong to a Post. The following contrived schemas can represent their relation.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const postSchema = Schema(
{
comments: [{ type: Schema.Types.ObjectId, ref: "Comment" }],
body: { type: String, unique: false, default: "" },
owner: {
ref: "User",
required: true,
type: Schema.Types.ObjectId,
},
},
{
timestamps: true,
}
);
const Post = mongoose.model("Post", postSchema);
module.exports = Post;
const commentSchema = Schema(
{
reactions: { type: Array },
body: { type: String, unique: false, default: "" },
post: { ref: "Post", required: true, type: Schema.Types.ObjectId },
owner: {
ref: "User",
required: true,
type: Schema.Types.ObjectId,
},
},
{
timestamps: true,
}
);
Now for commenting on a post.
STEP 4 or look inside of ./client/src/components/Post/Post.js.We need to add state to the CommentForm to collect the body of the comment, then send that data to our API after the user submits.
useState() hook.import React, { useState } from "react";
comment state var.const [comment, setComment] = useState("");
onChange prop of the Form.Control.onChange={(e) => setComment(e.target.value)}
import { useDispatch } from "react-redux";
dispatch() in the body of CommentForm.const dispatch = useDispatch();
onSubmit() which will be invoked when the form submits.const onSubmit = (e) => {
e.preventDefault();
dispatch();
};
onSubmit() to the form's onSubmit prop.onSubmit = { onSubmit };
./client/src/redux/actions.We don't have any redux actions related to comments...
comment.actions.js in ./client/src/redux/actions.This file will contain all the logic to making requests to our API.
import * as types from "../constants/comment.constants";
import api from "../api";
./client/src/redux/comment.constants.jsexport const CREATE_COMMENT = "POST.CREATE_COMMENT";
export const CREATE_COMMENT_SUCCESS = "POST.CREATE_COMMENT_SUCCESS";
export const CREATE_COMMENT_FAILURE = "POST.CREATE_COMMENT_FAILURE";
const createComment = (postId, body) => async (dispatch) => {
dispatch({ type: types.CREATE_COMMENT, payload: null });
try {
const res = await api.post(`/posts/${postId}/comments`, {
body,
});
dispatch({
type: types.CREATE_COMMENT_SUCCESS,
payload: res.data.data,
});
} catch (error) {
dispatch({ type: types.CREATE_COMMENT_FAILURE, payload: error });
}
};
export const commentActions = {
createComment,
};
./client/src/redux/actions/index.jsexport * from "./comment.actions";
commentActions into our Post component.import { commentActions } from "../../redux/actions";
dispatch()The function createComment() needs two arguments...
dispatch(commentActions.createComment());
postId to the comment form from the Post body.<CommentForm postId={props._id} />
CommentForm and send it along with comment to createComment().const CommentForm = (props) => {
const onSubmit = (e) => {
e.preventDefault();
dispatch(commentActions.createComment(props.postId, comment));
};
};

./server/routes/posts.api.js.We haven't defined a POST route for /posts/:id/comments.
router.post(
"/:id/comments",
authMiddleware.loginRequired,
postsController.createComment
);
createComment() in the controller.We create a comment given the data from the front end. We then update the post's comments with the new comment's id. Then we collect the comments of the post and send it back.
postController.createComment = async (req, res) => {
const comment = await Comment.create({
...req.body,
owner: req.userId,
post: req.params.id,
});
const post = await Post.findById(req.params.id);
post.comments.push(comment._id);
await post.save();
await post.populate("comments");
await post.execPopulate();
return sendResponse(res, 200, true, { post }, null, "Comment created!");
};
Comment as we use it.const Comment = require("../models/Comment");
