Redux News Reader

Hello Everyone I am stuck on Redux News Reader project.

Until this point I have red every forum post related and nothing seem to fix my problem.
I have not downloaded files yet.

Current behaviour => click on article and app gets stuck in loading comment phase :frowning:
Expected behaviour => click on article, see related comments and post comment

Here is my code

commentSlice.js

import {createSlice, createAsyncThunk} from '@reduxjs/toolkit';
// Create loadCommentsForArticleId here.
export const loadCommentsForArticleId = createAsyncThunk(
  'comments/loadCommentsforArticleId',
  async (id, thunkAPI) => {
    let response = await fetch(`api/articles/${id}/comments`);
    let json = await response.json();
    return json;
})
// Create postCommentForArticleId here.
export const postCommentForArticleId = createAsyncThunk(
  'comments/postCommentForArticleId',
  async ({articleId, comment}) => {
    let requestBody = JSON.stringify({comment: comment})
    let response = await fetch(`api/articles/${articleId}/comments`, {
      method: 'POST',
      body: requestBody,
    })
    let json = await response.json();
    return json;
  }
)
export const commentsSlice = createSlice({
  name: 'comments',
  initialState: {
    byArticleId: {},
    isLoadingComments: false,
    failedToLoadComments: false,
    createCommentIsPending: false,
    failedToCreateComment: false,
    // Add initial state properties here.
  },
  // Add extraReducers here.
  extraReducers: {
    [loadCommentsForArticleId.pending]: (state, action) => {
      state.isLoadingComments = true;
      state.failedToLoadComments = false;
    },
    [loadCommentsForArticleId.fulfiled]: (state, action) => {
      state.byArticleId = {[action.payload.articleId]: action.payload.comments};
      state.isLoadingComments = false;
      state.failedToLoadComments = false;
      state.isLoadingComments = false;
      state.failedToLoadComments = false;
    },
    [loadCommentsForArticleId.rejected]: (state, action) => {
      state.isLoadingComments = false;
      state.failedToLoadComments = true;
    },
    [postCommentForArticleId.pending]: (state, action) => {
      state.createCommentIsPending = true;
      state.failedToCreateComment = false;
    },
    [postCommentForArticleId.fulfiled]: (state, action) => {
      state.byArticleId[action.payload.articleId].push(action.payload);
      state.createCommentIsPending = false,
      state.failedToCreateComment = false
    },
    [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;

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.
useEffect(() => {
    if(article) {
      dispatch(loadCommentsForArticleId(article.id));
    }
  }, [article, dispatch]);

  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';

export default function CommentList({ comments }) {
  if (!comments) {
    return null;
  }
  
      return (
        <ul className='comments-list'>
            {comment.map(comment => {
              <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!
    dispatch(postCommentForArticleId({articleId, 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
          disable={isCreatePending}
          className='comment-button'
        >
          Submit
        </button>
      </div>
    </form>
  );
}

Probably I missed one letter or something my Dyslexia is kicking in :smiley:

Thanks for any help

I think this is where the issue is. You need to make it comments.map - with an s. Hope this helps.

Thank you very much. Unfortunately this was not the case

I have updated the code. wrapped the comment in “

  • ” and it did not helped as well

    import React from 'react';
    
    export default function CommentList({ comments }) {
      if (!comments) {
        return null;
      }
      
          return (
            <ul className='comments-list'>
                <li>{comments.map(comment => {
                  <Comment comment={comment} />
                })}</li>
            </ul>
        );
    }
  • Not a major issue, but you have two lines repeated. Probably a cut and paste error

    try changing to:

    return (
        <ul className='comments-list'>
        { 
          comments.map( individualComment =>        
              <Comment comment={individualComment} />
          )
        }
    
        </ul>
      );
    

    In the name you have a lower case F for for ie change it to ‘comments/loadCommentsForArticleId’

    Hello
    Thank you for your input. I have implemented what you suggeted. It looks like it is working now :slight_smile: :+1: