Redux工具包:如何在POST或PUT请求成功后发出GET请求?

whhtz7ly  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(163)

我制作了一个简单的待办事项列表应用程序来学习Redux Toolkit,在没有后端的情况下让它工作后,我决定添加一个简单的Flask服务器来练习使用Redux Toolkit的createAsyncThunk
我成功地创建了3个不同的异步thunk,用于用户获取他们的to-do、发布新的to-do或放置to-do。

import { createSlice, current, createAsyncThunk } from '@reduxjs/toolkit';
import axiosPrivate from '../../api/axios';

const initialState = {
    toDos: []
}

export const getToDos = createAsyncThunk('toDo/getToDos', async (user) => {
    const response = await axiosPrivate.get(`/to-dos/${user?.user?.firebase_uid}`, { headers: { 'Authorization': user?.idToken }, withCredentials: true });
    return response.data
})

export const addToDo = createAsyncThunk('toDo/addToDo', async ({ user, newToDo }) => {
    const response = await axiosPrivate.post('/to-dos/new', { userId: user?.user?.id, firebaseUid: user?.user?.firebase_uid, task: newToDo?.task }, { headers: { 'Authorization': user?.idToken }, withCredentials: true });
    const data = response.data
    return {data, user}
})

export const updateToDo = createAsyncThunk('toDo/updateToDo', async ({ user, toDoId, updateAttributes }) => {
    const response = await axiosPrivate.put('/to-dos/update', { userId: user?.user?.id, firebaseUid: user?.user?.firebase_uid, toDoId: toDoId, updateAttributes},  { headers: { 'Authorization': user?.idToken }, withCredentials: true })
    const data = response.data
    return {data, user}
})

export const toDosSlice = createSlice({
    name: 'toDos',
    initialState,
    reducers: {},
    extraReducers(builder) {
        builder
            .addCase(getToDos.fulfilled, (state, action) => {
                state.toDos = action.payload?.toDos
            })
            .addCase(addToDo.fulfilled, (action) => {
                getToDos(action?.payload?.user); // This does not change anything
            })
            .addCase(updateToDo.fulfilled, (action) => {
                getToDos(action?.payload?.user); // This does not change anything
            })
    }
})

export const { deleteToDo } = toDosSlice.actions;

export const selectToDos = (state) => state.toDos;

export default toDosSlice.reducer;

我遇到的问题是,在用户编辑了他们的toDo并将其标记为完成后,我不确定在哪里以及如何正确地从后端获取to-do。我知道我可以使用redux状态从技术上设置toDo的状态,并验证POST或PUT是否成功,尽管我想了解如何在此后使用GET请求正确地完成。
我的ToDoList组件,用户可以在其中删除或放置他们的ToDos,如下所示:

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import Stack from '@mui/material/Stack';
import Divider from '@mui/material/Divider';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import IconButton from '@mui/material/IconButton';
import DeleteIcon from '@mui/icons-material/Delete';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Checkbox from '@mui/material/Checkbox';
import Typography from '@mui/material/Typography';

import { getToDos, updateToDo, selectToDos } from '../toDoSlice';
import useAuth from '../../../hooks/useAuth';

function ToDoList() {
    const dispatch = useDispatch();
    const { user } = useAuth();
    const toDos = useSelector(selectToDos);

    useEffect(() => {
        dispatch(getToDos(user));
    }, [dispatch, user])

    const handleChange = (toDoId, updateAttributes) => {
        dispatch(updateToDo({ user, toDoId, updateAttributes }));
        // dispatch(getToDos(user)); // This sometimes causes the GET request to occur before the PUT request, which I don't understand    
    }

    return (
        <Stack spacing={2}>
            <Divider sx={{ marginTop: 5 }} />
            <Grid xs={4} item>
                {toDos?.toDos?.length ?
                    <Box>
                        <List>
                            {toDos?.toDos?.map((toDo) => (
                                <ListItem
                                    key={toDo?.id}
                                    secondaryAction={
                                        <IconButton
                                            edge="end"
                                            onClick={() => handleChange(toDo?.id, { 'deleted': !toDo?.deleted })}
                                        >
                                            <DeleteIcon />
                                        </IconButton>
                                    }
                                >
                                    <ListItemButton onClick={() => handleChange(toDo?.id, { 'completed': !toDo?.completed })}>
                                        <ListItemIcon>
                                            <Checkbox
                                                name={toDo.task}
                                                checked={toDo.completed}
                                                edge='start'
                                            />
                                        </ListItemIcon>
                                        <ListItemText
                                            primary={toDo.task}
                                            sx={{ textDecoration: toDo.completed ? 'line-through' : null }}
                                            primaryTypographyProps={{
                                                style: {
                                                    whiteSpace: 'nowrap',
                                                    overflow: 'hidden',
                                                    textOverflow: 'ellipsis'
                                                }
                                            }}
                                        />
                                    </ListItemButton>
                                </ListItem>
                            ))}
                        </List>
                    </Box>
                    : <Typography align='center' variant="h6" component="div" mt={2}>No To-Dos</Typography>
                }
            </Grid >
        </Stack >
    )
}

export default ToDoList

如何在POST或PUT操作之后执行GET请求?然后我应该将分派(getToDos(user))放在哪里?代码中的注解显示了我已经尝试过的方法的结果

mxg2im7a

mxg2im7a1#

在再次阅读Redux-Toolkit文档并查看其他SO帖子之后,我了解了执行asyncThunk连续调用的正确方法。
我没有在切片中执行它们,而是将调用移到了组件中,并使用Promises来执行它们。为了从请求中捕获错误并在组件中访问它,您必须在asyncThunk中使用Toolkit的rejectWithValue参数。
下面是一个例子:

export const loginUser = createAsyncThunk('user/loginUser', async (loginData, { rejectWithValue }) => {
    try {
        const response = await axios.post('/login', loginData);
        return response.data
    } catch (err) {
        if (!err.response) {
            throw err
        }
        return rejectWithValue(err.response.data)
    }
})

通过将{ rejectWithValue }添加到参数和return rejectWithValue(err.response.data),您可以访问组件中的响应,如下所示:

const handleSubmit = () => {
        if (loginData?.email && loginData?.password) {
            dispatch(loginUser(loginData))
                .unwrap()
                .then(() => {
                    // perform further asyncThunk dispatches here
                })
                .catch(err => {
                    console.log(err) // the return rejectWithValue(err.response.data) is sent here
                });
        }
    }

相关问题