I’ve recently been making blog pet project and encountered problem of posts having identical copies. Because of that when I try to add reactions to the post I keep getting next error It starts from 1 all the way to 100.
Warning: Encountered two children with the same key, 100
. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
They all have same data such as title, content, userId and id. I`m using react+reduxjs/toolkit+axios.
screenshot from react dev tool which shows that post components have identical copies
screenshot from web
This is postsSlice where I fetch data from API
import { createSlice, nanoid, createAsyncThunk } from "@reduxjs/toolkit";
import { sub } from 'date-fns';
import axios from "axios";
const POSTS_URL = 'https://jsonplaceholder.typicode.com/posts';
const initialState = {
posts: [],
status: 'idle',
error: null
}
export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
const response = await axios.get(POSTS_URL)
return response.data
})
export const addNewPosts = createAsyncThunk('posts/addNewPost', async (initialPost) => {
const response = await axios.post(POSTS_URL, initialPost)
return response.data
})
const postsSlice = createSlice({
name: 'posts',
initialState,
reducers: {
postAdded: {
reducer(state, action) {
state.posts.push(action.payload)
},
prepare(title, content, userId) {
return {
payload: {
id: nanoid(),
title,
content,
date: new Date().toISOString(),
userId,
reactions: {
thumbsUp: 0,
wow: 0,
heart: 0,
rocket: 0,
coffee: 0
}
}
}
}
},
reactionAdded(state, action) {
const { postId, reaction } = action.payload
const existingPost = state.posts.find(post => post.id === postId)
if (existingPost) {
existingPost.reactions[reaction]++
}
}
},
extraReducers(builder) {
builder
.addCase(fetchPosts.pending, (state, action) => {
state.status = 'loading'
})
.addCase(fetchPosts.fulfilled, (state, action) => {
state.status = 'succeeded'
// Adding date and reactions
let min = 1;
const loadedPosts = action.payload.map(post => {
post.date = sub(new Date(), { minutes: min++ }).toISOString();
post.reactions = {
thumbsUp: 0,
wow: 0,
heart: 0,
rocket: 0,
coffee: 0
}
return post;
});
// Add any fetched posts to the array
state.posts = state.posts.concat(loadedPosts)
})
.addCase(fetchPosts.rejected, (state, action) => {
state.status = 'failed'
state.error = action.error.message
})
.addCase(addNewPosts.fulfilled, (state, action) => {
action.payload.id = nanoid();
action.payload.userId = Number(action.payload.userId)
action.payload.date = new Date().toISOString();
action.payload.reactions = {
thumbsUp: 0,
wow: 0,
heart: 0,
rocket: 0,
coffee: 0
}
console.log(action.payload)
state.posts.push(action.payload)
})
}
})
export const selectAllPosts = (state) => state.posts.posts;
export const getPostsStatus = (state) => state.posts.status;
export const getPostsError = (state) => state.posts.error;
export const selectPostById = (state, postId) =>
state.posts.posts.find(post => post.id === postId);
export const { postAdded, reactionAdded } = postsSlice.actions
export default postsSlice.reducer
And here I render posts
import { useSelector, useDispatch } from "react-redux";
import PostsExcerpt from "./PostsExcerpt";
import { useEffect } from "react";
import {
selectAllPosts,
getPostsError,
getPostsStatus,
fetchPosts,
} from "../features/posts/postsSlice";
const PostList = () => {
const posts = useSelector(selectAllPosts);
const postsStatus = useSelector(getPostsStatus);
const error = useSelector(getPostsError);
const dispatch = useDispatch()
useEffect(()=>{
if(postsStatus === 'idle'){
dispatch(fetchPosts())
}
},[postsStatus, dispatch])
let content;
if(postsStatus==='loading'){
content = <p>Loading...</p>
} else if(postsStatus === 'succeeded'){
const orderedPosts = posts.slice().sort((a,b)=>b.date.localeCompare(a.date))
content = orderedPosts.map(post=> <PostsExcerpt key={post.id} post={post}/>)
} else {
content = <p>{error}</p>
}
return (
<section>
<h1>Posts</h1>
{content}
</section>
);
}
export default PostList;
I’ve tried to add nanoid
so every post would be unique. However it doesn`t seem to work.
zhans is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
1