Help, I'm completely stuck in Redux News Reader and I don't know how to proceed

I am stuck with this lesson: https://www.codecademy.com/paths/full-stack-engineer-career-path/tracks/fscp-redux/modules/redux-middleware-and-thunks/projects/redux-news-reader

I got up to section 9 in the project and when I click an article it just goes blank and won’t load anything. I have only edited commentSlice.js and comment.js. Please help me with this I am really confused by Redux and I don’t know what to do.

This is my code so far:
commentSlice.js
// Import createAsyncThunk and createSlice here.

import {createAsyncThunk, createSlice} from ‘@reduxjs/toolkit’;

// Create loadCommentsForArticleId here.

const loadCommentsForArticleId = createAsyncThunk(

“comments/loadCommentsForArticleId”,

async (id) => {

const request = await fetch(`api/articles/${id}/comments`);

const json = await request.json();

return json

}

);

// Create postCommentForArticleId here.

export const commentsSlice = createSlice({

name: ‘comments’,

initialState: {

// Add initial state properties here.

byArticleId: {},

isLoadingComments: false,

failedToLoadComments: false

},

// Add extraReducers here.

extraReducers: {

[loadCommentsForArticleId.pending]: (state, action) =>{

  state.isLoadingComments = true;

  state.failedToLoadComments = false;

},

[loadCommentsForArticleId.fulfilled]: (state, action) =>{

  state.byArticleId = action.payload;

  state.isLoadingComments = false;

  state.failedToLoadComments = false;

},

[loadCommentsForArticleId.rejected]: (state, action) =>{

  state.isLoadingComments = false;

  state.failedToLoadComments = 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;

comment.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.

useEffect(()=>{

if(article){

   dispatch(loadCommentsForArticleId(article.id));

   const commentsForArticleId = comments[article.id];

   console.log(commentsForArticleId);

}else{

  const commentsForArticleId = [];

}

});

if (commentsAreLoading) return

Loading Comments
;

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;

Hi there! I just finished this project and this part was pretty rough, I had the same problem at first. But looking through your code I noticed a couple things that could be causing the error.
In the loadCommentsForArticleId.fulfilled instance, instead of setting state.byArticleId to the action.payload, it needs to be

state.byArticleId[action.payload.articleId] = action.payload.comments

this loads the comments for the article with the correct id.
Next, I noticed that when I tried to handle the logic for commentsForArticleId inside the useEffect hook it caused this error, so I wrote it outside of useEffect with a ternary operator, and that helped. Lastly I think you forgot the useEffect’s dependency array? I might have missed it though. Hope this helps!

2 Likes

Hey thank you for the reply, this is very helpful.

I’m still having issues and like you said I narrowed it down to the useEffect hook.
For some reason if it is in my code the comments section of the website won’t load.

I have tried rewriting it like this:
if (typeof(article) === ‘undefined’){

 const commentsForArticleId = [];

}else{

useEffect(() => {

   dispatch(loadCommentsForArticleId(article.id));

 }, [dispatch, article]);

 const commentsForArticleId = comments[article.id];

}

Would you be able to show me how you wrote your use effect hook with defining the constant commentsForArticleId?

I managed to figure it out, thank you for your great tips!

Here is the final code:

//commentSlice.js

// Import createAsyncThunk and createSlice here.
import {createAsyncThunk, createSlice} from '@reduxjs/toolkit';
// Create loadCommentsForArticleId here.
export const loadCommentsForArticleId = createAsyncThunk(
  'comments/loadCommentsForArticleId',
  async (id) => {
    console.log("inside dispatch");
    const data = await fetch(`api/articles/${id}/comments`);
    const json = await data.json();
    return json;    
  }
);
// Create postCommentForArticleId here.
export const postCommentForArticleId = createAsyncThunk(
  'comments/postCommentForArticleId',
  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: {
    // 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.isLoadingComments = false;
        state.failedToLoadComments = false;
        state.byArticleId[action.payload.articleId] = action.payload.comments;
      })
      .addCase(loadCommentsForArticleId.rejected, (state, action) => {
        state.isLoadingComments = false;
        state.failedToLoadComments = true;
        state.byArticleId = {};
      })
      .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, action) => {
        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;

//comment.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.
  useEffect(() => {
    if(article){
      dispatch(loadCommentsForArticleId(article.id))
    }
  }, [article])
  //comments are inside an array and comments are objects.
  const commentsForArticleId = article ? comments[article.id]: []; 
  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>
  );
}


This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.