Redux News Reader Code Solution

Hi,

So there is no code solution for this project which I found annoying as In the past this is where I have learned a lot. I thought I would share my solution which appears to work in order to help others in a way I wish I could have been helped.

My code or solution is probably not the best and I am still very much learning React/Redux so please keep this in mind when you check out my code solution.

I struggled with this project and found coming back to it after a day really helped me see what I had to do and approach the challenge with a better “problem solver/learner” mindset rather than one of “just complete it and move on / frustration”.

Anyway, I just hope this can help… just click on the link and you can see the solution on Github.

Best of luck,
NT

25 Likes

Thank you!!! I will try to solve the exercise with your code. Thanks a lot!

Thanks, man, it actually works. Helped alot.

Thank You!!! I was missing one minuscule detail that drove me nuts for hours. This was a lifesaver

Thank you so much for posting this. It was nice to have something to check my code against. Was missing a few little bits here and there that was causing me to bang my head on the wall and now it makes sense. (had forgotten to export one thing)

I couldn’t get my code to work, all that rendered was “All Articles”, I tried your code and got the exact same thing! I’m at a loss here… Is it the API that somehow isn’t working correctly even though I’m not getting any error messages? I’m so confused :confused:

1 Like

I am also very new to Redux and all of this is coming off as “Hey, I’m doing it, but I dont exactly know how or why its working” With that said, I could be completely wrong about this, but shouldnt your extraReducers in commentSlice.js read "
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) => {
state.isLoadingComments = false;
state.failedToLoadComments = true;
})
"

It’s my understanding that pending will always be loading =true and failed= false, fulfilled will always be loading = false failed= false and rejected will always be loading = false failed= true.

Am I correct there?

2 Likes

Thank you you’re an absolute legend! Couldn’t figure out this assignment at all

Thank you for posting this excellent solution code, flavrfood! It really helped me work through the project.
I used map object notation for the extraReducers, here is that portion for anyone who tried to do it that way. I agree with bobcatbuckley about the boolean values.
Sandy

 extraReducers: {
    [loadCommentsForArticleId.pending]: (state) => {
      state.isLoadingComments  = true; 
      state.failedToLoadComments = false;
    }, 
    [loadCommentsForArticleId.fulfilled]: (state, action) => {
      state.byArticleId[action.payload.articleId] = action.payload.comments;
      state.isLoadingComments = false; 
      state.failedToLoadComments = false;
    }, 
    [loadCommentsForArticleId.rejected]: (state) => {
      state.isLoadingComments = false; 
      state.failedToLoadComments = true;
    }, 
    [postCommentForArticleId.pending]: (state) => {
      state.createCommentIsPending  = true; 
      state.failedToCreateComment = false;
    },
    [postCommentForArticleId.fulfilled]: (state, action) => {
     state.byArticleId[action.payload.articleId].push(action.payload);
      state.createCommentIsPending = false; 
      state.failedToCreateComment = false;
    },
    [postCommentForArticleId.rejected]: (state) => {
      state.createCommentIsPending = false; 
      state.failedToCreateComment = true;
    }
  }```
1 Like

Thanks @flavrfood - found this one very tedious to debug without having the files locally so your example has saved me a lot of frustration.

Thank you! This helped me complete the project!

Id say there is a good chance that you are blocking third party cookies in your browser settings, Ive just had the same issue after looking at my code for a couple of hours trying to figure out the issue it was just this setting. You can find it in your chrome browser privacy settings.

3 Likes

@flavrfood Thank you for your post. I was having a small problem with the added comments loading without having to refresh the article and your solution help me realize my coding mistake.

You are the best!!! this was driving me crazy!!! :smiley: Thank you!

1 Like

hello every it took me 5 hours try to figureout this project but finally i could do it

this is the code for each part
commentsSlice

// Import createAsyncThunk and createSlice here.
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";

// Create loadCommentsForArticleId here.
export const loadCommentsForArticleId = createAsyncThunk(
  "comments/loadCommentsForArticleId",
  async (id) => {
    const response = await fetch(`api/articles/${id}/comments`);
    const json = 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: {
    "comments/loadCommentsForArticleId/pending": (state, action) => {
      state.isLoadingComments = true;
      state.failedToLoadComments = false;
    },
    "comments/loadCommentsForArticleId/fulfilled": (state, action) => {
      state.byArticleId = {[action.payload.articleId]: action.payload.comments}
      state.isLoadingComments = false;
      state.failedToLoadComments = false;
    },
    "comments/loadCommentsForArticleId/rejected": (state, action) => {
      state.failedToLoadComments = true;
      state.isLoadingComments = false;
    },
    "comments/postCommentForArticleId/pending": (state, action) => {
      state.createCommentIsPending = true;
      state.failedToCreateComment = false;
    },
    "comments/postCommentForArticleId/rejected": (state, action) => {
      state.createCommentIsPending = false;
      state.failedToCreateComment = true;
    },
    "comments/postCommentForArticleId/fulfilled": (state, action) => {
     state.byArticleId[action.payload.articleId].push(action.payload)
      state.createCommentIsPending = false;
      state.failedToCreateComment = false;
    },
  },
});

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

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

  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

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} />
      ))}
    </ul>
  );
}

CommentsForm

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
          disabled={isCreatePending}
          className='comment-button'
        >
          Submit
        </button>
      </div>
    </form>
  );
}

this was hard but finally did it, hope you enjoy it, happy coding!!

ni ai wo wo ai ni , mixue gacor

check my blog bro https://kea.ke.hu/-/hola88/

It seems that frustration is part of Codecademy’s learning elements which, some of us get to figure out late in our path.

Thank you for posting your solution. It really helps

1 Like