redux async thunk,API不断响应待处理

发布于 2025-02-08 22:05:56 字数 7168 浏览 0 评论 0原文

我正在创建一个有关目标跟踪器的应用程序。当我从一个帐户注销时,一切都可以,除了注销陷入待处理状态。

控制台上也存在错误,说无法读取null(读取'token')dashboard.jsx的属性:20

dashboard.jsx

import React from 'react';
import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import GoalForm from '../components/GoalForm';
import Spinner from '../components/Spinner';
import { getGoals, reset } from '../features/goals/goalSlice';
import GoalItem from '../components/GoalItem';

function Dashboard() {
    const navigate = useNavigate();
    const dispatch = useDispatch();

    const { user } = useSelector(store => store.auth);
    const { goals, isLoading, isError, message } = useSelector(
        store => store.goals,
    );

    useEffect(() => {
        if (isError) console.log(message);
        if (!user) navigate('/login');

        dispatch(getGoals());

        return () => {
            dispatch(reset());
        };
    }, [user, isError, message, navigate, dispatch]);

    if (isLoading) return <Spinner />;

    return (
        <>
            <section className='heading'>
                <h1>Welcome {user && user.name}</h1>
                <p>Goals Dashboard</p>
            </section>
            <GoalForm />

            <section className='content'>
                {goals.length > 0 ? (
                    <div className='goals'>
                        {goals.map(goal => (
                            <GoalItem key={goal._id} goal={goal} />
                        ))}
                    </div>
                ) : (
                    <h3>You have not set any goals</h3>
                )}
            </section>
        </>
    );
}

export default Dashboard;

goartlice.js

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

const initialState = {
    goals: [],
    isError: false,
    isSuccess: false,
    isLoading: false,
    message: '',
};

// Create goal
export const createGoal = createAsyncThunk(
    'goals/create',
    async (goalData, thunkAPI) => {
        try {
            const token = thunkAPI.getState().auth.user.token;

            return await goalService.createGoal(goalData, token);
        } catch (error) {
            const message =
                (error.response &&
                    error.response.data &&
                    error.response.data.message) ||
                error.message ||
                error.toString();

            return thunkAPI.rejectWithValue(message);
        }
    },
);

// Get Goals
export const getGoals = createAsyncThunk('goals/get', async (_, thunkAPI) => {
    try {
        const token = thunkAPI.getState().auth.user.token;

        return await goalService.getGoals(token);
    } catch (error) {
        const message =
            (error.response && error.response.data && error.response.data.message) ||
            error.message ||
            error.toString();

        return thunkAPI.rejectWithValue(message);
    }
});

// Delete goal
export const deleteGoal = createAsyncThunk(
    'goals/delete',
    async (id, thunkAPI) => {
        try {
            const token = thunkAPI.getState().auth.user.token;
            return await goalService.deleteGoal(id, token);
        } catch (error) {
            const message =
                (error.response &&
                    error.response.data &&
                    error.response.data.message) ||
                error.message ||
                error.toString();
            return thunkAPI.rejectWithValue(message);
        }
    },
);

export const goalSlice = createSlice({
    name: 'goal',
    initialState,
    reducers: {
        reset: state => initialState,
    },
    extraReducers: builder => {
        builder
            .addCase(createGoal.pending, state => {
                state.isLoading = true;
            })
            .addCase(createGoal.fulfilled, (state, action) => {
                state.isLoading = false;
                state.isSuccess = true;
                state.goals.push(action.payload);
            })
            .addCase(createGoal.rejected, (state, action) => {
                state.isLoading = false;
                state.isError = true;
                state.message = action.payload;
            })
            .addCase(getGoals.pending, state => {
                state.isLoading = true;
            })
            .addCase(getGoals.fulfilled, (state, action) => {
                state.isLoading = false;
                state.isSuccess = true;
                state.goals = action.payload;
            })
            .addCase(getGoals.rejected, (state, action) => {
                state.isLoading = false;
                state.isError = true;
                state.message = action.payload;
            })
            .addCase(deleteGoal.pending, state => {
                state.isLoading = true;
            })
            .addCase(deleteGoal.fulfilled, (state, action) => {
                state.isLoading = false;
                state.isSuccess = true;
                state.goals = state.goals.filter(
                    goal => goal._id !== action.payload.id,
                );
            })
            .addCase(deleteGoal.rejected, (state, action) => {
                state.isLoading = false;
                state.isError = true;
                state.message = action.payload;
            });
    },
});

export const { reset } = goalSlice.actions;
export default goalSlice.reducer;

goalservice.js

import axios from 'axios';

const API_URL = '/api/goals';

// Create goal
const createGoal = async (goalData, token) => {
    const config = {
        headers: {
            'x-auth-token': `${token}`,
        },
    };

    const response = await axios.post(API_URL, goalData, config);

    return response.data;
};

// Get goals
const getGoals = async token => {
    const config = {
        headers: {
            'x-auth-token': `${token}`,
        },
    };

    const response = await axios.get(API_URL, config);

    return response.data;
};

// Delete goal
const deleteGoal = async (goalId, token) => {
    const config = {
        headers: {
            'x-auth-token': `${token}`,
        },
    };

    const response = await axios.get(`${API_URL}/${goalId}`, config);
    // console.log(response);

    return response.data;
};

const goalService = {
    createGoal,
    getGoals,
    deleteGoal,
};

export default goalService;

,这是注销部分:builder.addcase.addcase(lokout.fulfill.fulfield,state =&gt {state.user = null}); 当我尝试注销时,用户将被记录出来,但错误会连续出现,例如重新渲染页面。该页面本身重新渲染,状态被困在注销中。 删除目标也不起作用

I am creating an app about goal tracker. When I logout from an account, everything goes okay except the the logout gets stuck in pending state.

There is also error in console saying Cannot read properties of null (reading 'token') Dashboard.jsx:20.

Dashboard.jsx

import React from 'react';
import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import GoalForm from '../components/GoalForm';
import Spinner from '../components/Spinner';
import { getGoals, reset } from '../features/goals/goalSlice';
import GoalItem from '../components/GoalItem';

function Dashboard() {
    const navigate = useNavigate();
    const dispatch = useDispatch();

    const { user } = useSelector(store => store.auth);
    const { goals, isLoading, isError, message } = useSelector(
        store => store.goals,
    );

    useEffect(() => {
        if (isError) console.log(message);
        if (!user) navigate('/login');

        dispatch(getGoals());

        return () => {
            dispatch(reset());
        };
    }, [user, isError, message, navigate, dispatch]);

    if (isLoading) return <Spinner />;

    return (
        <>
            <section className='heading'>
                <h1>Welcome {user && user.name}</h1>
                <p>Goals Dashboard</p>
            </section>
            <GoalForm />

            <section className='content'>
                {goals.length > 0 ? (
                    <div className='goals'>
                        {goals.map(goal => (
                            <GoalItem key={goal._id} goal={goal} />
                        ))}
                    </div>
                ) : (
                    <h3>You have not set any goals</h3>
                )}
            </section>
        </>
    );
}

export default Dashboard;

goalSlice.js

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

const initialState = {
    goals: [],
    isError: false,
    isSuccess: false,
    isLoading: false,
    message: '',
};

// Create goal
export const createGoal = createAsyncThunk(
    'goals/create',
    async (goalData, thunkAPI) => {
        try {
            const token = thunkAPI.getState().auth.user.token;

            return await goalService.createGoal(goalData, token);
        } catch (error) {
            const message =
                (error.response &&
                    error.response.data &&
                    error.response.data.message) ||
                error.message ||
                error.toString();

            return thunkAPI.rejectWithValue(message);
        }
    },
);

// Get Goals
export const getGoals = createAsyncThunk('goals/get', async (_, thunkAPI) => {
    try {
        const token = thunkAPI.getState().auth.user.token;

        return await goalService.getGoals(token);
    } catch (error) {
        const message =
            (error.response && error.response.data && error.response.data.message) ||
            error.message ||
            error.toString();

        return thunkAPI.rejectWithValue(message);
    }
});

// Delete goal
export const deleteGoal = createAsyncThunk(
    'goals/delete',
    async (id, thunkAPI) => {
        try {
            const token = thunkAPI.getState().auth.user.token;
            return await goalService.deleteGoal(id, token);
        } catch (error) {
            const message =
                (error.response &&
                    error.response.data &&
                    error.response.data.message) ||
                error.message ||
                error.toString();
            return thunkAPI.rejectWithValue(message);
        }
    },
);

export const goalSlice = createSlice({
    name: 'goal',
    initialState,
    reducers: {
        reset: state => initialState,
    },
    extraReducers: builder => {
        builder
            .addCase(createGoal.pending, state => {
                state.isLoading = true;
            })
            .addCase(createGoal.fulfilled, (state, action) => {
                state.isLoading = false;
                state.isSuccess = true;
                state.goals.push(action.payload);
            })
            .addCase(createGoal.rejected, (state, action) => {
                state.isLoading = false;
                state.isError = true;
                state.message = action.payload;
            })
            .addCase(getGoals.pending, state => {
                state.isLoading = true;
            })
            .addCase(getGoals.fulfilled, (state, action) => {
                state.isLoading = false;
                state.isSuccess = true;
                state.goals = action.payload;
            })
            .addCase(getGoals.rejected, (state, action) => {
                state.isLoading = false;
                state.isError = true;
                state.message = action.payload;
            })
            .addCase(deleteGoal.pending, state => {
                state.isLoading = true;
            })
            .addCase(deleteGoal.fulfilled, (state, action) => {
                state.isLoading = false;
                state.isSuccess = true;
                state.goals = state.goals.filter(
                    goal => goal._id !== action.payload.id,
                );
            })
            .addCase(deleteGoal.rejected, (state, action) => {
                state.isLoading = false;
                state.isError = true;
                state.message = action.payload;
            });
    },
});

export const { reset } = goalSlice.actions;
export default goalSlice.reducer;

goalService.js

import axios from 'axios';

const API_URL = '/api/goals';

// Create goal
const createGoal = async (goalData, token) => {
    const config = {
        headers: {
            'x-auth-token': `${token}`,
        },
    };

    const response = await axios.post(API_URL, goalData, config);

    return response.data;
};

// Get goals
const getGoals = async token => {
    const config = {
        headers: {
            'x-auth-token': `${token}`,
        },
    };

    const response = await axios.get(API_URL, config);

    return response.data;
};

// Delete goal
const deleteGoal = async (goalId, token) => {
    const config = {
        headers: {
            'x-auth-token': `${token}`,
        },
    };

    const response = await axios.get(`${API_URL}/${goalId}`, config);
    // console.log(response);

    return response.data;
};

const goalService = {
    createGoal,
    getGoals,
    deleteGoal,
};

export default goalService;

And this is logout part: builder.addCase(logout.fulfilled, state => {state.user = null});
When i try to logout, the user is logged out but the error appears continuously, like re-rendering the page. The page is re-rendered itself and state is stuck in logout.
Delete Goal is also not working

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

逆夏时光 2025-02-15 22:05:56

您必须在尝试获取目标之前检查用户是否已登录

useEffect(() => {
        if (isError) console.log(message);

        if (!user) {
           navigate('/login');
        } else {
           dispatch(getGoals());
        }

        return () => {
            dispatch(reset());
        };
    }, [user, isError, message, navigate, dispatch]);

You must check if the user is logged in before attempt to get the goals

useEffect(() => {
        if (isError) console.log(message);

        if (!user) {
           navigate('/login');
        } else {
           dispatch(getGoals());
        }

        return () => {
            dispatch(reset());
        };
    }, [user, isError, message, navigate, dispatch]);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文