首页 > 解决方案 > 用于 CRUD 操作的 Redux Toolkit Slice Race Condition

问题描述

我在使用时遇到了竞争条件问题createSlice,我认为这可能源于对它们的正确使用的误解。问题的症结在于我正在创建一个表示特定资源的 CRUD 操作的切片,并且希望通过使用单个状态标志来保持简单。在下面的人为示例中,我有一个posts用于创建和获取帖子的切片:

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { postAPI } from './postAPI'

const createPost = createAsyncThunk(
  'posts/createPost',
  async (post, thunkAPI) => {
    const response = await postAPI.createPost(post)
    return response.data
  }
)

const fetchPosts = createAsyncThunk(
  'posts/fetchPosts',
  async (userId, thunkAPI) => {
    const response = await postAPI.fetchPosts(userId)
    return response.data
  }
)

const postsSlice = createSlice({
  name: 'posts',
  initialState: { 
       posts: [], 
       status: 'idle' 
  },
  reducers: {
  },
  extraReducers: {
    //
    // Fetch Posts
    //

    // Update the status flag to pending
    [fetchPosts.pending]: (state, action) => {
      state.status = 'pending'
    },
    // Update the list of posts
    [fetchPosts.fulfilled]: (state, action) => {
      state.status = 'success'
      state.posts = action.payload
    },
    // Fetching failed, update the status to reflect this
    [fetchPosts.rejected]: (state, action) => {
      state.status = 'failed'
    },
  },

    //
    // Create Post
    //

    // Update the status flag to pending
    [createPost.pending]: (state, action) => {
      state.status = 'pending'
    },
    // Update the list of posts after the post has been successfully created,
    // (the postAPI will return the created post on success)
    [createPost.fulfilled]: (state, action) => {
      state.status = 'success'

      // Add the new post to the state array
      state.posts.push(action.payload)
    },
    // Creation failed, update the status to reflect this
    [createPost.rejected]: (state, action) => {
      state.status = 'failed'
    },
  },
})

获取和创建本身就可以很好地工作:

我的帖子页面...

export const MyPosts = (props) => {
    const { userId }  = props;
    const dispatch = useDispatch();
    const { status, posts } = useSelector(state => state.posts);
 
    useEffect(() => {
        dispatch(fetchPosts(userId));
    }, [dispatch, userId]);

    if (status === 'pending') {
        display loading message...
    }

    if (status === 'error') {
        display error message...
    }

    return (
        ...
        { status === 'success' && 
            <Posts {posts} = {posts}/>
        }
        ...
    );
};

创建帖子页面...

export const CreatePost = (props) => {
    const { post }  = props;
    ...
    const onCreatePostButtonClicked = () => {
        dispatch(createPost(post)).then(...);
    };
    ...

    return (
        <Button onClick={(event) => { createPost() } }.../>
    );
};

但是,问题如下:用户在“创建帖子”页面上创建帖子,导致state对象具有status标志success,然后导航到“我的帖子”页面。状态标志尚未重置,因此当“我的帖子”组件呈现时,该status标志仍​​设置为success,导致Posts返回{ status === 'success...块中的内容,而不是加载消息。

我对该问题的最初解决方案是添加一个reset减速器来重置state对象useEffect,但这会导致额外的问题并且使用起来很麻烦。

我现在的解决方案是简单地将额外的标志添加到state,但这感觉就像一个杂物。有没有办法确保渲染新组件时state对象的状态标志?pending还是这种方法不正确(每个 CRUD 操作我应该有不同的切片)?我似乎无法在网上找到任何slice同时具有实体获取和创建的示例。

标签: reactjsreduxreact-reduxredux-toolkit

解决方案


推荐阅读