我正尝试用react和redux做一个简单的博客网页(沿着教程)。我创建了一个redux商店,我做了一个posts切片,用来管理所有与帖子相关的东西,我在使用redux thunk获取数据时遇到了一些问题。当我运行博客页面时,我看到每个帖子都有两个。不确定这个问题是否来自我用来调度fetchPosts的组件()函数并显示帖子或切片本身中的一些错误。下面是我的代码和项目中的一个jsFiddle。如果有人能帮我检查我哪里出错了,我将非常感激。
PostsList.js
const PostsList = () => {
const dispatch = useDispatch();
const posts = useSelector(selectAllPosts);
const postStatus = useSelector(getPostsStatus);
const error = useSelector(getPostsError);
useEffect(() => {
if (postStatus === "idle") {
dispatch(fetchPosts());
}
}, [postStatus, dispatch]);
let content;
if (postStatus === "loading") {
content = <p>"Loading..."</p>;
} else if (postStatus === "succeeded") {
const orderedPosts = posts
.slice()
.sort((a, b) => b.date.localeCompare(a.date));
content = orderedPosts.map((post) => (
<PostsExcerpt key={post.id} post={post} />
));
} else if (postStatus === "failed") {
content = <p>{error}</p>;
}
return (
<section>
<h2>Posts</h2>
{content}
</section>
);
};
export default PostsList;
PostsSlice.js
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,
};
//Fetch Posts Function
export const fetchPosts = createAsyncThunk("posts/fetchPosts", async () => {
const response = await axios.get(POSTS_URL);
return response.data;
});
export const addNewPost = 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) => {
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(addNewPost.fulfilled, (state, action) => {
// Fix for API post IDs:
// Creating sortedPosts & assigning the id
// would be not be needed if the fake API
// returned accurate new post IDs
const sortedPosts = state.posts.sort((a, b) => {
if (a.id > b.id) return 1;
if (a.id < b.id) return -1;
return 0;
});
action.payload.id = sortedPosts[sortedPosts.length - 1].id + 1;
// End fix for fake API post IDs
action.payload.userId = Number(action.payload.userId);
action.payload.date = new Date().toISOString();
action.payload.reactions = {
thumbsUp: 0,
hooray: 0,
heart: 0,
rocket: 0,
eyes: 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 { postAdded, reactionAdded } = postsSlice.actions;
export default postsSlice.reducer;
这就是结局
如果没有什么我怀疑是错误的问题,这是一个github回购与我的代码。谢谢
我尝试更改切片、fetchPosts函数和PostsList组件,但仍然没有结果。
1条答案
按热度按时间3b6akqbq1#
问题是useEffect will be called twice on mount since React 18 when you are in development under Strict Mode。
在
PostsList
中,这意味着您可能没有意识到您正在调度fetchPosts
两次。dispatch(fetchPosts())
我们可以在Redux devtools中看到这种情况。
然后在
PostSlice
中,将第二个fetchPosts
形实转换的结果连接到第一个fetchPost
形实转换结果的末尾。state.posts = state.posts.concat(loadedPosts)
而是将此行更改为:
state.posts = loadedPosts;