Redux 同构渲染实战与优化方案

阅读时长 10 分钟读完

Redux 是一个状态管理工具,它可以让开发者更容易地管理前端应用的状态。然而,在实际应用中,随着应用的复杂度不断提升,Redux 在服务端渲染(SSR)和同构渲染方面存在一些问题,可能会引起一些性能和可维护性方面的挑战。在本文中,我们将介绍如何在同构渲染中使用 Redux,并提供优化方案,以获得更好的性能和开发体验。

常规 Redux 在 SSR 中存在的问题

在 SSR 中,数据应该在服务端先加载,在 HTML 发送给客户端之前注入到页面中,以增强应用的性能和用户体验。然而,Redux 的默认方式是将状态存储在客户端,在客户端渲染完整个页面后再加载数据。因此,在同构渲染中使用 Redux 需要考虑以下问题:

  1. 首次渲染时页面将会较慢。 页面的首次渲染可能需要等待请求发送服务器,等待服务器返回并解析数据或等待其他客户端逻辑完成。
  2. 数据加载可能会被重复进行。 首次请求会在服务器端实现,多次请求会在客户端重复进行。
  3. 请求和渲染的顺序可能会导致 UI 闪烁。 如果数据请求与渲染不同步,那么,页面很有可能会闪烁,用户体验差。

Redux 同构渲染实战

针对上述问题,我们可以借助一些技术手段解决:

服务器端渲染

用服务器渲染来提升页面性能。首先,我们需要对 React 应用进行 SSR。可以借助第三方库,如 Next.jsGatsby.js,它们提供了丰富的配置,可以将应用程序的页面完全渲染到 HTML、CSS 和 JavaScript 中,并且这些页面很容易高效缓存。

-- -------------------- ---- -------
------ ----- ---- -------
------ - -------------- - ---- ------------------
------ - -------- - ---- -------------
------ --- ---- -------

----- ------- - ------------------
----- --- - ---------
----- ---- - ----

------------ ----- ---- -- -
  ----- ----- - ----------------
  ----- ---- - ---------------
    --------- --------------
      ---- --
    -----------
  -
  ----------
    --------- -----
    ------
      ------
        ------------ --- ---------------
      -------
      ------
        ---- -----------------------
        --------
          ------------------------ - ------------------------------------
        ---------
        ------- ------------------------
      -------
    -------
  --
--

---------------- -- -- -
  ------------------- -- --------- -- ---- ---------
--

如上所示,我们可以在服务器端将应用程序的碎片完全渲染到 HTML、CSS 和 JavaScript 中,并将初始状态序列化到内联脚本中。当页面首次加载时,客户端 JavaScript 可以使用这个状态,从而不需要再次加载数据。

开发同构 Action

Next.js 和 Gatsby.js 能在服务器和客户端公用相同的代码和组件。如果常规的 Redux 中间件被用来处理在客户端中产生的 Action,例如通过触发 Redux 操作更改路由,不能工作的事件,那么同一个 Action 会在服务端重复发送。

一种方式是“请求桥梁”或“Action 桥梁模式”。我们为每个 Action 创建一个服务器端方法。这些方法由客户端代码调用,它们会在服务端异步执行相应的 Action。

-- -------------------- ---- -------
-- ----------------------
------ ----- ---------- - -------------
------ ----- --------- - -- -- -- ----- ---------- ---

-- ----------------------
------ ----- --------- - -- -- ----- ---------- --------- -- -
  ----- ---- - ----- -------------
  ---------- ----- ----------- -------- ---- ---
--

在服务端 Rehydration 状态

在客户端 JavaScript 加载时,Redux 的初始状态是从服务器端渲染中服务端使用 JSON.stringify() 序列化的对象中。我们需要 React 同构渲染提供的“hydrate”方法,使这些更新和重新填充需要更新的组件,而不需要重复渲染应用程序。

-- -------------------- ---- -------
------ ----- ---- -------
------ - ------- - ---- -----------
------ - -------- - ---- -------------
------ --- ---- -------
------ -------------- ---- ------------------------

----- ----- - ----------------------------------------

--------
  --------- --------------
    ---- --
  ------------
  -------------------------------
-

Server-side Rendering 期间消除无关代码

在服务器端,我们可以根据初始状态编写精简版本的 reducer。我们可以使用 Redux 提供的 createStore 函数,在每个页面请求时生成不同的 store。

-- -------------------- ---- -------
-- --------------------------
------ - ----------- - ---- -------
------ ----------- ---- --------------------
------ - --------- - ---- -----------
------ - ------------- ------------ - ---- -------------------

----- ------------- - -- -- -
  ------ --- ----------------- ------- -- -
    ----- ----- - ------------------------
    ---------------- ----- ------------ --
    -----
      ----------------------
      -------- -- -
        ---------------- ----- ------------ --
        --------------
      --
      ---------- -- ------------
  --
-

------ ------- --------------

当我们在服务端渲染过程中执行 loadDataStore 时,我们只需要根据页面请求中的 url,选择需要在我们的组件中展示哪个 reducer。在组件渲染完成后,可以简化为只保留与当前页面相关的(例如选定的页面或板块),从而令处理程序速度更快。

在客户端启用预加载

要减少客户端 JavaScript 加载时间,我们可以使用 React suspense。 一旦页面获得客户端的控制权时,我们可以使用预加载,从而在加载视图时同时加载所需的组件和数据。

-- -------------------- ---- -------
-- ------------------
------ ----- ---- -------
------ - ------- - ---- -------------
------ - --------- - ---- -----------

----- ---------- - ------------- -- ------------------------
----- ---------- - ------------- -- ------------------------

----- --- ------- --------------- -
  ------------------- -
    ----- - --------- - - ----------
    -----------
  -

  -------- -
    ------ -
      --------------- ---------------------------------
        ----------- --
        ----------- --
      -----------------
    -
  -
-

----- ------------------ - ---------- -- -
  ------ -
    ---------- -- -- -
      ---------------------
    -
  -
-

------ ------- ------------- -------------------------

如上所示,当客户端代码首次加载时,预加载选定的组件。 这样,当客户端 JavaScript 得到控制并生成组件时,预加载组件中的数据立即可用。

优化方案

虽然 Redux 应用程序可以进行 SSR,但在实际应用中性能问题会很常见。这是由于同一数据可能会在客户端和服务器上进行多次请求,并且大多数时候这些请求和渲染的顺序都没有被优化,导致页面 UI 闪烁和性能问题。下面是一些可以优化的方案。

使用 Redux 动态模块加载(Code Splitting)

对于大型应用程序,需要使用动态模块加载来拆分代码模块并更改需加载的方式。 这大大缩短了页面加载时间。 Webpack 4 支持用于代码分割创建动态导入的语法,可以使其更容易使用。

-- -------------------- ---- -------
------ - ----- -------- - ---- --------

----- -------------- - ------- -- ----------------------------

-------- ------------- -
  ------ -
    -----
      --------- ---------------------------------
        --------------- --
      -----------
    ------
  --
-

如上所示,你可以延迟加载任何组件或资产,这将使页面更快。 让你的客户端跑得更快。

使用强制缓存

为了减少服务器响应时间并提高性能,可以启用“强制缓存”,这样服务器不必在每个页面请求时都发送相同的内容。通常情况下,我们可以利用 Webpack 的缓存分离来分离缓存文件。

-- -------------------- ---- -------
----- ---- - ----------------
----- ------------- - ----------------------------------

-------------- - -
  ------ ------------
  ------- -
    ----- ----------------------- --------
    --------- ----------
  --
  -------- ---- ----------------------------
--

如上所示,我们启用了 workbox-webpack-plugin 插件来自动生成 Service Worker,其中结合了“缓存格外的查找”策略,用户第一次访问 Web 应用程序时返回静态内容,然后缓存。 下次客户端资源请求将直接从缓存中获取,而不是从服务端再次获取。

结论

在本文中,我们介绍了如何在同构渲染中使用 Redux,并提供了一些优化方案,以获得更好的性能和开发体验。虽然同构渲染在一些方面存在挑战,但使用上述技术可使我们更简单地处理 Redux 在服务端渲染和同构渲染方面的问题。 了解这些技术将帮助开发人员更好地掌握 Redux 的能力,用它来构建可维护的大型应用程序,并提高 Web 应用程序的性能和用户体验。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/672ed790eedcc8a97c8b01ac

纠错
反馈