Redux News Reader

Hello, I have been driving myself crazy trying to figure out why my code refuses to work render or add to the comments section of this project and have found through the forums that my solutions are pretty spot on and that I shouldn’t have any issues. Please see code below. Need a fresh set of eyes on it!

commentsSlice.js

// Import createAsyncThunk and createSlice here. import {createAsyncThunk, createSlice} from '@reduxjs/toolkit'; // Create loadCommentsForArticleId here. export const loadCommentsForArticleId = createAsyncThunk( 'comments/loadComments', 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/postComment', async({articleId, comment}) => { const requestBody = JSON.stringify({comment: 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: { //initial comment state properties: byArticleId: {}, isLoadingComments: false, failedToLoadComments: false, //post comment properties: createCommentIsPending: false, failedToCreateComment: false }, extraReducers: { [loadCommentsForArticleId.pending]: (state, action) => { isLoadingComments = true; failedToLoadComments = false; }, [loadCommentsForArticleId.fulfilled]: (state, action) => { state.byArticleId = {[action.payload.articleId]: action.payload.comments}; isLoadingComments = false; failedToLoadComments = false; }, [loadCommentsForArticleId.rejected]: (state, action) => { isLoadingComments = false; failedToLoadComments = true; }, [postCommentForArticleId.pending]: (state, action) => { createCommentIsPending = true; failedToCreateComment = false; }, [postCommentForArticleId.fulfilled]: (state, action) => { const articleId = action.payload.articleId; state.byArticleId[articleId].push(action.payload); createCommentIsPending = false; failedToCreateComment = false; }, [postCommentForArticleId.rejected]: (state, action) => { createCommentIsPending = false; 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;

Comments.js

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); // Dispatch loadCommentsForArticleId with useEffect here. const commentsForArticleId = article ? comments[article.id] : []; 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;

CommentList.js

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) => { return <Comment comment={comment} /> }) } </ul> ); }

CommentForm.js

import React, { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { createCommentIsPending, postCommentForArticleId } from '../features/comments/commentsSlice'; export default function CommentForm({ articleId }) { const dispatch = useDispatch(); const [comment, setComment] = useState(''); // Declare isCreatePending here. const isCreatePending = useSelector(createCommentIsPending); const handleSubmit = (e) => { e.preventDefault(); // dispatch your asynchronous action here! console.log(comment); dispatch(postCommentForArticleId({ articleId: article.id, comment: comment }) ) setComment(''); }; return ( <form onSubmit={handleSubmit}> <label for='comment' className='label'> Add Comment: </label> <div id='input-container'> <input id='comment' value={comment} onChange={(e) => setComment(e.currentTarget.value)} type='text' /> <button disabled={isCreatePending} className='comment-button' > Submit </button> </div> </form> ); }

I’m not 100% sure, but here’s what I think:

I think something is going wrong in commentSlice.js on line 45. It looks like you are setting state.byArticleId to an object. Instead, you want to assign a value to one of the properties of state.byArticleId.

So state.byArticleId, at property action.payload.articleId should be set to action.payload.comments.

I think it would look about like this:
state.byArticleId[action.payload.articleId] = action.payload.comments;

Hope that helps!