我用redux-toolkit做了一个公告板应用。我使用了jsonPlacehlder fake API作为应用程序的内容。但是从API获取数据后,在UI上显示数据时,每个对象显示2次。我从API获取的总数据是100。但由于这个问题,它显示200数据的UI上.每个物体2次。所有必要的代码如下所示。请帮助解决这个问题。
PostSlice.js中的代码:
import { createSlice, nanoid,createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
import { sub } from "date-fns";
const POSTS_URL = 'http://jsonplaceholder.typicode.com/posts';
const initialState = {
posts: [],
status: 'idle',
error: null
}
export const fetchPosts = createAsyncThunk('posts/getPosts', async () => {
const response = await axios.get(POSTS_URL);
// console.log(response.data)
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: {
like: 0,
love: 0,
wow: 0,
coffee: 0
}
}
}
}
},
addReactions(state, action) {
const { postId, reaction } = action.payload;
const postToReact = state.posts.find(post => post.id === postId);
if(postToReact){
postToReact.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 because they are not available in the api data
let min = 1;
const loadedPosts = action.payload.map(post => {
post.date = sub(new Date(), {minutes: min++}).toISOString();
post.reactions = {
like: 0,
love: 0,
wow: 0,
coffee: 0
}
return post;
})
state.posts = state.posts.concat(loadedPosts);
})
.addCase(fetchPosts.rejected, (state, action) => {
state.status = 'failed';
state.error = action.error.message
})
}
});
export const selectAllPost = state => state.posts.posts;
export const getPostStatus = state => state.posts.status;
export const getPostError = state => state.posts.error;
export const { postAdded, addReactions } = postsSlice.actions
export default postsSlice.reducer;
从PostList.js组件中获取代码以显示所有帖子:
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import Post from './Post';
import { selectAllPost, getPostStatus, getPostError, fetchPosts } from '../../features/posts/postsSlice';
import { parseISO } from 'date-fns';
const PostsList = () => {
const dispatch = useDispatch()
const posts = useSelector(selectAllPost);
const postStatus = useSelector(getPostStatus);
const postError = useSelector(getPostError);
useEffect(() => {
if (postStatus === 'idle') {
dispatch(fetchPosts())
}
}, [postStatus, dispatch])
let content;
if(postStatus === 'loading'){
content = <span className="loading loading-bars loading-lg"></span>
} else if(postStatus === 'succeeded') {
const sortedPosts = posts.slice().sort((a, b) => parseISO(b.date) - parseISO(a.date));
content = sortedPosts.map((post, index) =>
<Post key={index} post={post} />
);
console.log(sortedPosts)
} else if(postStatus === 'failed') {
content = {postError}
}
return (
<div>
<h1 className='text-center text-2xl font-bold mb-4'>Posts</h1>
{content}
</div>
)
}
export default PostsList;
1条答案
按热度按时间jum4pzuy1#
有几件事导致了重复状态:
1.该应用被渲染到一个
React.StrictMode
组件中,该组件在非生产构建中应用一些额外的逻辑,以帮助检测应用代码中的问题。在这种情况下,它是由修复双渲染发现的错误或修复重新运行效果发现的错误引起的。换句话说,获取posts数据的副作用是运行两次,发出两个API请求,第二个请求的数据附加到第一个请求的数据上。
要解决此问题,您可以执行以下一项或多项操作:
fetchPosts.fulfilled
reducer case以替换posts状态,而不是追加到它。fetchPosts
操作上使用cancel/abort令牌,以便在组件卸载/装载时取消任何正在进行的API请求。请参阅Redux-Toolkit取消文档了解更多细节。联系我们
postSlice.js -检查
fetchPosts
是否被中止,仅为未中止的API请求设置错误状态。Demo