延迟加载的 React 路由器无论如何都会路由加载

2024-03-12

我一直在尝试使用 React.lazy 和 Suspense 在 React 中延迟加载路由。但无论当前路径如何,某些组件都会加载:Feed、Profile 和 Settings。

请注意,我实际上并不想延迟加载像 MenuAppBar 和 SnackAlert 这样的组件,但如果我正常导入它们并删除它们的 Suspense,则直接进行代码分割甚至不起作用,所有内容都会加载,整个应用程序只是一个块。

import {createMuiTheme, MuiThemeProvider} from "@material-ui/core";
import {yellow} from "@material-ui/core/colors";
import CssBaseline from "@material-ui/core/CssBaseline";
import axios from "axios";
import React, {lazy, Suspense, useEffect, useState} from "react";
import {BrowserRouter as Router, Route, Switch} from "react-router-dom";
import "./css/feed.css";
import "./css/style.css";

const Feed = lazy(() => import("./routes/Feed"));
const Profile = lazy(() => import("./routes/Profile"));
const Home = lazy(() => import("./routes/Home"));
const Settings = lazy(() => import("./routes/Settings"));
const NotFound = lazy(() => import("./routes/NotFound"));
const MenuAppBar = lazy(() => import("./components/MenuAppBar"));
const SnackAlert = lazy(() => import("./components/SnackAlert"));

const App: React.FC = () => {
    const [isLogged, setIsLogged] = useState(localStorage.getItem("token") ? true : false);

    const [user, setUser] = useState<User>(
        isLogged ? JSON.parse(localStorage.getItem("userInfo") as string) : {admin: false}
    );
    const [openError, setOpenError] = useState<boolean>(false);
    const [errorMsg, setErrorMsg] = useState<string>("");
    const [severity, setSeverity] = useState<Severity>(undefined);
    const [pwa, setPwa] = useState<any>(null);
    const [showBtn, setShowBtn] = useState<boolean>(false);
    const [isLight, setIsLight] = useState<boolean>(
        (JSON.parse(localStorage.getItem("theme") as string) as boolean) ? true : false
    );

    const theme: customTheme = {
        darkTheme: {
            palette: {
                type: "dark",
                primary: {
                    main: yellow[600]
                }
            }
        },
        lightTheme: {
            palette: {
                type: "light",
                primary: {
                    main: yellow[700]
                }
            }
        }
    };

    window.addEventListener("beforeinstallprompt", (event) => {
        event.preventDefault();
        setPwa(event);
        setShowBtn(true);
    });

    window.addEventListener("appinstalled", (e) => {
        setShowBtn(false);
        setErrorMsg("App installed!");
        setSeverity("success");
        setOpenError(true);
    });

    const handleClick = () => {
        if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
            setErrorMsg(`Please, open the share menu and select "Add to Home Screen"`);
            setSeverity("info");
            setOpenError(true);
        } else {
            if (pwa) {
                pwa.prompt();
                pwa.userChoice.then((choiceResult: {outcome: "accepted" | "refused"}) => {
                    if (choiceResult.outcome === "accepted") {
                        setErrorMsg("App downloading in the background..");
                        setSeverity("info");
                        setOpenError(true);
                    }
                    setPwa(null);
                });
            }
        }
    };

    useEffect(() => {
        const token: string | null = localStorage.getItem("token");
        let userInfo: User = JSON.parse(localStorage.getItem("userInfo") as string);
        if (userInfo && token && !userInfo.admin) {
            setUser(userInfo);
            setIsLogged(true);
        }
        if (isLogged) {
            axios
                .get("/api/auth/user", {
                    headers: {
                        "x-auth-token": `${token}`
                    }
                })
                .then((res) => {
                    if (!userInfo || !token) {
                        setUser(res.data as User);
                    }
                    localStorage.setItem(`userInfo`, JSON.stringify(res.data as User));
                    setIsLogged(true);
                })
                .catch((err) => {
                    if (err) {
                        setIsLogged(false);
                    }
                });
        } else {
            localStorage.removeItem("token");
            localStorage.removeItem("userInfo");
        }
    }, [isLogged]);

    return (
        <MuiThemeProvider theme={isLight ? createMuiTheme(theme.lightTheme) : createMuiTheme(theme.darkTheme)}>
            <CssBaseline />
            <Router>
                <Suspense fallback={<div></div>}>
                    <Route
                        path="/"
                        render={() => (
                            <>
                                <MenuAppBar
                                    isLogged={isLogged}
                                    setIsLogged={setIsLogged}
                                    user={user}
                                    setUser={setUser}
                                    isLight={isLight}
                                    setIsLight={setIsLight}
                                />
                                <SnackAlert severity={severity} errorMsg={errorMsg} setOpenError={setOpenError} openError={openError} />
                            </>
                        )}
                    />
                </Suspense>
                <Suspense fallback={<div></div>}>
                    <Switch>
                        <Route exact path="/" render={() => <Home />} />

                        <Route exact path="/profile/:id" render={() => <Profile />} />

                        <Route exact path="/feed" render={() => <Feed isLogged={isLogged} user={user} />} />

                        <Route
                            exact
                            path="/settings"
                            render={() => (
                                <Settings isLight={isLight} setIsLight={setIsLight} handleClick={handleClick} showBtn={showBtn} />
                            )}
                        />
                        <Route render={() => <NotFound />} />
                    </Switch>
                </Suspense>
            </Router>
        </MuiThemeProvider>
    );
};

export default App;

你正在包裹你的整个Switch在一个单一的Suspense,因此所有组件将同时延迟加载。您可能只希望在第一次渲染特定路由时获取/加载每个路径。

<Switch>
  <Route
    exact
    path="/"
    render={props => (
      <Suspense fallback={<div>Loading...<div>}>
        <Home {...props} />
      </Suspense>
    )}
  />
  <Route
    exact
    path="/profile/:id"
    render={props => (
      <Suspense fallback={<div>Loading...<div>}>
        <Profile {...props} />
      </Suspense>
    )}
  />
  <Route
    exact
    path="/feed"
    render={() => (
      <Suspense fallback={<div>Loading...<div>}>
        <Feed isLogged={isLogged} user={user} {...props} />
      </Suspense>
    )}
  />
  <Route
    exact
    path="/settings"
    render={() => (
      <Suspense fallback={<div>Loading...<div>}>
        <Settings
          isLight={isLight}
          setIsLight={setIsLight}
          handleClick={handleClick}
          showBtn={showBtn}
          {...props}
        />
      </Suspense>
    )}
  />
  <Route
    render={() => <NotFound />}
  />
</Switch>

这里有很多重复,所以将悬念分解成 HOC 是很实用的。

const withSuspense = (WrappedComponent, fallback) => props => (
  <Suspense fallback={fallback}>
    <WrappedComponent {...props} />
  </Suspense>
);

您可以装饰每个透视默认导出,即

export default withSuspense(Home, <div>Loading...<div>);

App.js

...
<Switch>
  <Route exact path="/" render={props => <Home {...props} />} />

或在您的应用程序中装饰它们

const HomeWithSuspense = withSuspense(Home, <div>Loading...<div>);

...

<Switch>
  <Route
    exact
    path="/"
    render={props => <HomeWithSuspense {...props} />}
  />
  ...
</Switch>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

延迟加载的 React 路由器无论如何都会路由加载 的相关文章

  • React 无法识别 DOM 元素上的 `isActive` 属性 - styled-components

    我有以下内容svg我传递道具的组件 import React from react export default props gt
  • 无法验证 CSRF 令牌的真实性 Rails/React

    我的 Rails 应用程序中有一个 React 组件 我正在尝试使用它fetch 发送一个POST对于我在本地主机上托管的 Rails 应用程序 这给了我错误 ActionController InvalidAuthenticityToke
  • 有没有办法显示嵌套在 Grid 组件内的 Material-UI 抽屉?

    我正在使用 Material UI 创建一个 Web 应用程序 主页分为 3 个网格 每个网格有一个height of 500px 我想在中间网格内显示一个带有一些操作选项的抽屉 那可能吗 到目前为止 我只能在整个屏幕上显示它 这是我的主要
  • 发生错误。", ExceptionMessage: "提供的 'HttpContent' 实例无效

    尝试将文件添加到 http 休息调用时出现此错误 responseJson 消息 发生错误 ExceptionMessage 提供了无效的 HttpContent 实例 它确实 正在使用 多部分 参数名称 内容 异常类型 System Ar
  • 了解 React Native 中的默认字体大小

    在过去的几个月里 我一直在开发一个 React Native 应用程序 但有些事情总是让我困惑 而我现在正试图弄清楚它的真相 我正在尝试标准化应用程序中的字体大小 正文 标题等 并且正在努力了解 React Native 究竟从哪里获取默认
  • 监听 redux 动作

    我想创建一个可重用的 redux 表模块 它将存储和更新页码 显示的总页数等 我可以在所有页面之间共享这些模块 但是 我需要更新操作来触发刷新数据操作 该操作将根据页面到达不同的端点 因此 可能类似于页面特定的监听 RefreshData
  • 创建 html 结构,每个 li 中仅允许 3 个 div 元素。在 React + underscore.js 中

    这是以下内容的位副本如何创建每个 li 中仅允许 3 个 div 元素的 html 结构 在 React underscore js 中 https stackoverflow com questions 38008023 how to c
  • 如何使用 jest 通过 Promise.all 设置多次提取测试

    我在测试中使用 jest 我正在使用 React 和 Redux 并且执行以下操作 function getData id notify return dispatch gt dispatch anotherFunction Promise
  • 过滤嵌套的 JSON 对象

    我有一个搜索栏 您可以在其中输入员工姓名 它应该根据过滤器返回姓名 我有一个嵌套的 JSON 对象 如下所示 我需要深入了解该对象以访问数组中的员工姓名 您可以看到我尝试实现的多个选项 它们已被注释掉 我的问题是代码没有过滤名称并返回所有名
  • 如何解决此错误“不要使用对象作为类型”?

    我不明白这个错误消息造成的 我的组件有两个和一个包含对象的数据数组 我收到一条错误消息 不要使用object作为一种类型 这object类型目前很难使用 我该如何解决它 我附加了数组包含对象的数据 first tsx import data
  • 将 sass 变量导入 gatsby 组件中引用的第二个 Sass 文件

    我正在使用 Gatsby 构建一个静态站点项目 我已经成功安装了 gatsby sass 插件并让 sass 正常工作 但是 我无法将自定义 sass 变量文件正确导入到其他组件 sass 文件中 下面是我的文件夹结构 src compon
  • Facebook SDK 登录/注销 ngrok

    我正在尝试将我正在构建的网络应用程序与 Facebook 集成 Facebook 现在要求所有 API 调用都必须从 https 站点进行 我正在构建的这个应用程序只是为了好玩 所以我使用的是 localhost 我在用着ngrok将我的请
  • React this.state 未定义?

    我正在遵循 Pluralsight 的初学者教程 在表单提交时将值传递给addUser组件方法 我需要将 userName 推送到this state users但我收到错误 App jsx 14 Uncaught TypeError Ca
  • ReactJS 水平对齐material-ui 元素

    我试图在文本输入旁边有一个单选按钮 这样用户基本上可以输入问题的 答案 并标记一个首选答案 然而 Material UI 将每个都放在自己的行上 这就是我目前所拥有的 div div
  • s3 中托管的静态网站:页面刷新后返回 404

    使用此存储桶策略 Version 2012 10 17 Statement Sid PublicReadGetObject Effect Allow Principal Action s3 GetObject Resource arn aw
  • 如何从react-bootstrap复选框获取值/属性?

    我正在尝试使用反应引导复选框 https react bootstrap github io components html forms controls https react bootstrap github io components
  • React 中的变异状态有哪些缺点?

    我有一个带有顶级组件和许多嵌套子组件的 React 应用程序 顶级组件是唯一具有状态的组件 该状态采用单个变量的形式 this state g new BlackJackGame g 包含一个复杂的数据结构 class BlackJackG
  • 有什么方法可以复制 div 的渲染 HTML 吗?

    我正在开发电子邮件签名生成器 我想通过按按钮复制最终签名 而不是手动选择签名并将其复制到剪贴板 这意味着我需要它们的图像 文本和样式 我尝试了几种变体 包括 w3schools 的变体 但没有成功 其中一些只是复制文本 但没有样式 例子 h
  • 如何在create-react-app中注入没有REACT_APP前缀的dotenv变量?

    我有一个项目要从旧版 React 应用程序迁移到标准版create react app一个 未弹出 在遗留项目中 它手动加载 env文件与dotenv and dotenv expand并通过webpack注入DefinePlugin cr
  • React中如何触发同级组件的函数?

    I am new to front end world and could not figure out how to trigger a function from a sibling component Lets say I have

随机推荐

  • 从 pandas 中具有多个值的列创建虚拟对象

    我正在寻找一种Python式的方法来处理以下问题 The pandas get dummies 方法非常适合从数据帧的分类列创建虚拟对象 例如 如果该列的值位于 A B get dummies 创建 2 个虚拟变量并相应地分配 0 或 1
  • 如何使用 Spring Jdbctemplate.update(String sql, obj...args) 获取插入的 id

    我正在使用 Jdbctemplate 我需要插入查询的 id 我读到我必须构建一个特定的PreparedStatement 并使用GenerateKeyHolder 对象 问题是在我的应用程序中所有插入方法都使用此 JdbcTemplate
  • 如何使用 AJAX 请求打开 jQuery UI 对话框?

    在我的网页上有一个 jQuery UI 对话框 当我单击按钮 创建新用户 时 它会打开一个新窗口 我的问题是如何使用 AJAX 请求打开该窗口 从另一个页面打开对话框表单会很好 例如 dialog html div title Create
  • Log4J 1.2 属性配置器 -> Log4J2

    目前 我们的应用程序使用 Log4J 1 2 并使用以下任一方式对其进行配置 File file PropertyConfigurator configure file getAbsolutePath or URL url Property
  • Mailgun:消息“已接受”,但需要很长时间才能送达(或未送达)

    我正在将 Mailgun 用于我维护的网站 通常 Mailgun 工作得很好 但我遇到了一个奇怪的问题 我的脚本调用 HTTP API 使用 Mailgun 发送消息 然后这些消息在我的日志中显示为 已接受 但随后需要很长时间才能 传送 通
  • 获取 HTML 元素中单击位置的文本

    我有一个包含一些文本的 div 元素 当用户单击该 div 内的单词时 我想突出显示该单词 为了做到这一点 我需要知道点击发生在文本中的哪个字符位置 这样我就可以找到附近的空白并在单词周围插入一些格式 找出文本中点击发生的位置是这里的技巧
  • 自动完成后端

    这是一个面试问题 设计一个自动完成的分布式后端 我会回答如下 自动完成是按给定后缀在字典中进行搜索 这本词典可能应该被组织为trie 该词典是根据最常见的查询构建的 但这是另一回事了 现在我假设字典不会经常更改 例如每天一次而不是每毫秒一次
  • 使用断言的最佳实践?

    使用是否存在性能或代码维护问题assert作为标准代码的一部分而不是仅将其用于调试目的 Is assert x gt 0 x is less than zero 比更好或更差 if x lt 0 raise Exception x is l
  • C++ 初始化数组指针

    如何初始化指向文字数组的指针 我希望 grid 指向新分配的 int 数组 1 2 3 int grid new int 3 grid 1 2 3 谢谢 你不能初始化这样就可以动态分配数组 你也不能assign以这种方式到数组 动态或静态
  • 在 OSX 上编译 clisp-2.49:未找到 LIBFFI

    TL DR Even if libffi似乎已安装 configure即使我给它添加 正确的 前缀 脚本也找不到它 这篇文章的最后一部分 是我陷入困境的地方 我仅提供其他信息来解释我如何到达那里 我对这篇长篇文章表示歉意 如果有些内容与您无
  • Git 克隆:“您似乎克隆了一个空存储库”

    我和一些同事一直致力于一个存储在私人 git 存储库中的项目 历史上没有问题 但最近我尝试克隆 遇到了以下问题 Cloning into project warning You appear to have cloned an empty
  • 限制从 Linq 列表中返回的结果数

    我正在使用 Linq EF4 1 从数据库中提取一些结果 并希望将结果限制为 X 个最新结果 其中X是用户设置的数字 有没有办法做到这一点 我目前正在将它们作为List如果这有助于限制结果集 虽然我可以通过循环来限制这一点 直到我点击 X
  • 默认 GNU 链接器脚本名称,以便 VIM 进行语法突出显示

    链接描述文件的常用后缀是什么 以便 VIM 对其使用语法突出显示 好像是 ld 仅据我所知 Vim 没有提供它的语法文件 至少我的没有 7 3 尝试提供下载的内容here http vim 1045645 n5 nabble com Syn
  • 优化内存密集型数据流管道的 GCP 成本

    我们希望降低在 GCP Dataflow 中运行特定 Apache Beam 管道 Python SDK 的成本 我们构建了一个内存密集型 Apache Beam 管道 每个执行器上运行需要大约 8 5 GB RAM 当前正在加载一个大型机
  • C :警告:赋值使指针来自整数而不进行强制转换[默认启用]

    这是我的代码 include
  • Flink TaskManager 超时?

    我正在运行 Flink 应用程序 通过 Yarn 似乎有时任务管理器会随机超时 这是错误 java util concurrent TimeoutException Heartbeat of TaskManager with id some
  • 将日期与 data.table 包一起使用

    我最近发现了 data table 包 现在想知道是否应该替换我的一些 plyr 代码 总而言之 我真的很喜欢plyr 并且我基本上实现了我想要的一切 然而 我的代码运行了一段时间 并且加快速度的前景足以让我运行一些测试 这些测试很快就结束
  • 使用 jQuery 的 Jenkins json REST api 和 CORS 请求

    我正在尝试使用 Jenkins json API 但无法使身份验证正常工作 setup 詹金斯安全 Jenkin s own user database access Matrix gebaseerde beveiliging CORS 通
  • 'Mysql:Class 的未定义方法初始化'

    我的 MySQL 服务器安装一直遇到问题 在断电后变得混乱 配置 运行 OS X 10 6 5 的 Intel i5 Mac已安装红宝石 1 9 2已安装 Rails 3 0 1MySQL 服务器 最终 安装并运行我完全重新安装了MySQL
  • 延迟加载的 React 路由器无论如何都会路由加载

    我一直在尝试使用 React lazy 和 Suspense 在 React 中延迟加载路由 但无论当前路径如何 某些组件都会加载 Feed Profile 和 Settings 请注意 我实际上并不想延迟加载像 MenuAppBar 和