I have been at this one for a while now. I have been able to get everything to work and just this last thing isn’t happening.
When I post a comment I get this in the console…
MSW] 10:01:16 POST /api/articles/undefined/comments (200)
and I cannot understand why the ${articleId}
part of the url is coming back undefined?
I am going to post all of my code here in hopes that someone can help me find what I am missing.
// Import createAsyncThunk and createSlice here.
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
// Create loadCommentsForArticleId here.
export const loadCommentsForArticleId = createAsyncThunk(
"comments/loadCommentsForArticleID",
async (articleID) => {
const response = await fetch(`api/articles/${articleID}/comments`);
const json = await response.json();
return json;
}
);
// Create postCommentForArticleId here.
export const postCommentForArticleId = createAsyncThunk(
"comments/postCommentForArticleId",
async ({ articleId, comment }) => {
const requestBody = JSON.stringify({ comment });
const response = await fetch(`api/articles/${articleId}/comments`, {
method: "POST",
body: requestBody,
});
const json = await response.json();
return json;
}
);
export const commentsSlice = createSlice({
name: "comments",
initialState: {
// Add initial state properties here.
byArticleId: {},
isLoadingComments: false,
failedToLoadComments: false,
createCommentIsPending: false,
failedToCreateComment: false,
},
// Add extraReducers here.
extraReducers: (builder) => {
builder
.addCase(loadCommentsForArticleId.pending, (state) => {
state.isloadingComments = true;
state.failedToLoadComments = false;
})
.addCase(loadCommentsForArticleId.fulfilled, (state, action) => {
state.isLoading = false;
state.failedToLoadComments = false;
state.byArticleId = {
[action.payload.articleId]: action.payload.comments,
};
})
.addCase(loadCommentsForArticleId.rejected, (state) => {
state.isLoading = false;
state.failedToLoadComments = true;
})
.addCase(postCommentForArticleId.pending, (state) => {
state.createCommentIsPending = true;
state.failedToCreateComment = false;
})
.addCase(postCommentForArticleId.fulfilled, (state, action) => {
state.createCommentIsPending = false;
state.failedToCreateComment = false;
state.byArticleId = [action.payload.articleId].push(action.payload);
})
.addCase(postCommentForArticleId.rejected, (state) => {
state.createCommentIsPending = false;
state.failedToCreateComment = true;
});
},
});
export const selectComments = (state) => state.comments.byArticleId;
export const isLoadingComments = (state) => state.comments.isLoadingComments;
export const createCommentIsPending = (state) =>
state.comments.createCommentIsPending;
export default commentsSlice.reducer;
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
loadCommentsForArticleId,
selectComments,
isLoadingComments,
} from "../comments/commentsSlice";
import { selectCurrentArticle } from "../currentArticle/currentArticleSlice";
import CommentList from "../../components/CommentList";
import CommentForm from "../../components/CommentForm";
const Comments = () => {
const dispatch = useDispatch();
const article = useSelector(selectCurrentArticle);
// Declare additional selected data here.
const comments = useSelector(selectComments);
const commentsAreLoading = useSelector(isLoadingComments);
const commentsForArticleId = article ? comments[article.id] : [];
// Dispatch loadCommentsForArticleId with useEffect here.
useEffect(() => {
if (article) {
dispatch(loadCommentsForArticleId(article.id));
}
}, [dispatch, article]);
if (commentsAreLoading) return <div>Loading Comments</div>;
if (!article) return null;
return (
<div className="comments-container">
<h3 className="comments-title">Comments</h3>
<CommentList comments={commentsForArticleId} />
<CommentForm articleId={article.id} />
</div>
);
};
export default Comments;
import React from "react";
import Comment from "./Comment";
export default function CommentList({ comments }) {
if (!comments) {
return null;
}
return (
<ul className="comments-list">
{comments.map((comment) => (
<Comment comment={comment} key={comment.id} />
))}
</ul>
);
}