I’m near the end of this challenge Redux News Reader and now stuck in the postCommentForArticleId.fulfilled
reducer section. When I submit a new comment it’s supposed to add the new comment, but instead I get a blank entry (image below).
It may be related to how I’m either passing the arguments (e.g. in CommentForm.js, commentSlice.js, etc.). But I would like someone to take a look at my files to see if they know what I did wrong.
I left my gist here.
commentSlice.js
// 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 = await response.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`)
const json = await response.json()
return json
}
)
export const commentsSlice = createSlice({
name: 'comments',
initialState: {
// Add initial state properties here.
byArticleId: {
// 123: ['Great article', 'I disagree.'],
},
isLoadingComments: false,
failedToLoadComments: false,
createCommentIsPending: false,
failedToCreateComment: false,
},
// Add extraReducers here.
extraReducers: (builder) => {
// loadCommentsForArticleId
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
})
// postCommentForArticleId
builder
.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;
Comment.js
// 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 = await response.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`)
const json = await response.json()
return json
}
)
export const commentsSlice = createSlice({
name: 'comments',
initialState: {
// Add initial state properties here.
byArticleId: {
// 123: ['Great article', 'I disagree.'],
},
isLoadingComments: false,
failedToLoadComments: false,
createCommentIsPending: false,
failedToCreateComment: false,
},
// Add extraReducers here.
extraReducers: (builder) => {
// loadCommentsForArticleId
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
})
// postCommentForArticleId
builder
.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;
CommentList.js
// 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 = await response.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`)
const json = await response.json()
return json
}
)
export const commentsSlice = createSlice({
name: 'comments',
initialState: {
// Add initial state properties here.
byArticleId: {
// 123: ['Great article', 'I disagree.'],
},
isLoadingComments: false,
failedToLoadComments: false,
createCommentIsPending: false,
failedToCreateComment: false,
},
// Add extraReducers here.
extraReducers: (builder) => {
// loadCommentsForArticleId
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
})
// postCommentForArticleId
builder
.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;
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 handleSubmit = (e) => {
e.preventDefault();
// dispatch your asynchronous action here!
console.log('comment', comment)
dispatch(postCommentForArticleId({articleId,comment}))
setComment('');
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor='comment' className='label'>
Add Comment:
</label>
<div id='input-container'>
<input
id='comment'
value={comment}
onChange={(e) => setComment(e.currentTarget.value)}
type='text'
/>
<button
className='comment-button'
>
Submit
</button>
</div>
</form>
);
}