首页 > web前端 > js教程 > 正文

React-Redux 应用中实现用户数据的条件加载

DDD
发布: 2025-10-22 12:06:30
原创
328人浏览过

React-Redux 应用中实现用户数据的条件加载

本教程旨在解决 react-redux 应用中未登录用户不必要地请求用户数据和敏感 api key 导致 401 错误的问题。我们将通过在 redux thunk 中引入认证状态检查机制,并结合组件层面的状态判断,实现用户数据的按需加载,从而优化应用性能并提升用户体验。

在构建基于 React 和 Redux 的认证应用时,一个常见的挑战是如何确保只有在用户登录后才尝试加载其专属数据或需要认证的敏感资源。如果应用在初始化时无条件地发起这些请求,未登录用户将会收到大量的 401 Unauthorized 错误,这不仅会污染开发者工具的控制台,还会造成不必要的网络请求,影响应用性能。

问题根源分析

根据提供的代码示例,问题主要来源于 App.js 中的 useEffect 钩子:

  1. store.dispatch(loadUser()):在应用启动时无条件地分发 loadUser action。
  2. axios.get('/api/stripeapikey'):同样在应用启动时无条件地请求 Stripe API Key。

loadUser action 内部通过 axios.get('/api/profile') 尝试获取用户资料。如果用户当前没有有效的认证会话(例如,尚未登录或认证 token 已过期),后端 API 会拒绝这些请求并返回 401 状态码,从而导致前端出现错误。

解决方案:基于认证状态的条件加载

为了解决这个问题,核心思想是在发起这些需要认证的请求之前,先检查用户的认证状态。我们可以通过以下两种主要方式实现:

  1. 在 Redux Thunk 内部检查: 在 loadUser action creator 中,利用 Redux Thunk 提供的 getState 函数访问当前 Redux 状态,判断用户是否已认证。这种方法将认证检查逻辑封装在 action 内部,使得 loadUser 无论从何处调用都能保持一致的按需加载行为。
  2. 在组件中检查: 在 App.js 的 useEffect 中,使用 useSelector 获取认证状态,然后有条件地 dispatch loadUser 或请求 Stripe API Key。

本教程将结合这两种方法:loadUser 动作在 Thunk 内部进行认证检查,而 Stripe API Key 的请求则在 App.js 中基于 Redux 状态进行判断。

AppMall应用商店
AppMall应用商店

AI应用商店,提供即时交付、按需付费的人工智能应用服务

AppMall应用商店 56
查看详情 AppMall应用商店

实现用户数据的条件加载

首先,我们需要修改 loadUser Redux Thunk,引入 getState 参数来访问 Redux store 的当前状态。在发起 API 请求之前,检查 getState().auth.isAuthenticated(假设 auth reducer 中有一个 isAuthenticated 字段表示用户是否登录)。

// actions/user.js
import axios from 'axios';

export const loadUser = () => async (dispatch, getState) => {
    // 在尝试加载用户之前,检查用户是否已认证
    // 假设 Redux 状态中有一个 auth.isAuthenticated 字段
    if (!getState().auth.isAuthenticated) {
        // 如果用户未认证,则直接返回,不执行后续的 API 请求
        // 这样可以避免在未登录状态下发起不必要的 /api/profile 请求
        return;
    }

    try {
        dispatch({ type: 'LOAD_USER_REQ' });

        // 注意:根据您的代理配置,API 路径可能是 '/api/profile'
        const { data } = await axios.get('/api/profile'); 

        dispatch({
            type: 'LOAD_USER_SUCCESS',
            payload: data.user
        });

    } catch (error) {
        // 即使进行了预检查,API 请求仍可能因其他原因失败(如 token 过期),
        // 此时应处理错误,并将认证状态设为 false。
        dispatch({
            type: 'LOAD_USER_FAIL',
            payload: error.response && error.response.data.message
                ? error.response.data.message
                : error.message
        });
    }
};

export const clearErrors = () => async dispatch => {
    dispatch({ type: 'CLEAR_ERRORS' });
};
登录后复制

对应的 Reducer 状态管理:

为了使上述检查生效,authReducer 必须正确地管理 isAuthenticated 状态。isAuthenticated 应该在用户成功登录/注册后设为 true,在登出或加载用户失败时设为 false。

// reducers/user.js
const initialState = {
    user: null, // 初始用户数据设为 null
    isAuthenticated: false, // 初始认证状态为 false
    loading: false,
    error: null
};

export const authReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'LOAD_USER_REQ':
            return {
                ...state,
                loading: true,
                error: null
            };

        case 'LOAD_USER_SUCCESS':
            return {
                ...state,
                loading: false,
                isAuthenticated: true,
                user: action.payload,
                error: null
            };

        case 'LOAD_USER_FAIL':
            return {
                ...state,
                loading: false,
                isAuthenticated: false, // 加载失败,视为未认证
                user: null, // 清空用户数据
                error: action.payload
            };

        // 假设您有登录/注册/登出相关的 action
        // case 'LOGIN_SUCCESS':
        // case 'REGISTER_SUCCESS':
        //     return { ...state, loading: false, isAuthenticated: true, user: action.payload, error: null };
        // case 'LOGOUT_SUCCESS':
        //     return { ...state, loading: false, isAuthenticated: false, user: null, error: null };

        case 'CLEAR_ERRORS':
            return {
                ...state,
                error: null
            };

        default:
            return state;
    }
};
登录后复制

实现 Stripe API Key 的条件加载

对于 Stripe API Key,由于它在 App.js 的 useEffect 中直接通过 axios 请求,我们可以利用 useSelector 从 Redux store 中获取认证状态,然后有条件地执行请求。

// App.js
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import axios from 'axios';
import { useSelector } from 'react-redux'; // 导入 useSelector

import Header from './components/Header';
import Home from './components/Home';
import Payment from './components/Payment';
import Profile from './components/Profile';

import { loadUser } from './actions/user';
import store from './store';

export default function App() {
    const [stripeApiKey, setStripeApiKey] = useState('');
    // 从 Redux store 中获取认证状态
    const { isAuthenticated } = useSelector(state => state.auth); 

    useEffect(() => {
        // 无论用户是否认证,都尝试 dispatch loadUser。
        // loadUser thunk 内部会根据 isAuthenticated 状态决定是否发起 API 请求。
        store.dispatch(loadUser());

        // 只有当用户已认证时才请求 Stripe API Key
        if (isAuthenticated) {
            (async () => {
                try {
                    const { data } = await axios.get('/api/stripeapikey');
                    setStripeApiKey(data.stripeApiKey);
                } catch (error) {
                    console.error('Failed to load Stripe API Key:', error);
                    // 可以在此添加错误处理,例如 dispatch 一个 action 来更新 Redux 状态
                }
            })();
        } else {
            // 如果用户未认证,确保清空或重置 stripeApiKey
            setStripeApiKey('');
        }

    }, [isAuthenticated]); // 依赖 isAuthenticated,当认证状态改变时重新运行此 effect

    return (
        <Router>
            <div className="App">
                <Header />
                <Routes>
                    <Route path="/" element={<Home />} />
                    {/* 这些路由可能需要额外的路由保护
登录后复制

以上就是React-Redux 应用中实现用户数据的条件加载的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号