详解React ISR如何实现Demo

 更新时间:2023年07月07日 09:58:57   作者:嘿嘿不务正业  
这篇文章主要为大家介绍了React ISR如何实现Demo详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

什么是 ISR

之前写了两个 demo 讲解了如何实现 SSR 和 SSG,今天再写个 demo 说在 ISR 如何实现。

ISR 即 Incremental Static Regeneration 增量静态再生,是指在 SSG 的前提下,可以在收到请求时判定页面是否需要刷新,如果需要则重新构建该页面,这样既拥有了静态页面的优势又可以避免页面长时间未更新导致信息过时。且由于在页面维度验证,所以每次可以只构建特定的页面。

ISR 一般适用于符合 SSG 场景,但是却对页面的时限性有一定要求时。

如何实现

简单的 ISR 实现也很简单,只需要在收到页面请求时按照更新策略判断是否需要需要重新生成页面,如果需要触发页面的构建更新。需要注意一般情况下生成页面不会影响页面的响应,而是后台去做构建。

现在就基于之前写的 SSG demo,做一下改造让其支持 ISR

修改构建脚本

由于 ISR 构建会同时在构建脚本和服务器中触发,所以需要对之前的代码做一些小小的改动。

首先抽离出一个通用的构建函数(由于服务器会使用到尽量避免同步代码):

import fs from 'fs/promises';
import { renderToString } from 'react-dom/server';
import React from 'react';
import Post from './ui/Post';
import List from './ui/List';
async function build(type: 'list'): Promise<void>;
async function build(type: 'post', name: string): Promise<void>;
async function build(type: 'list' | 'post', name?: string) {
    if (type === 'list') {
        const posts = await fs.readdir('posts');
        await fs.writeFile(
            'dist/index.html',
            `<div id="root">${renderToString(
                <List
                    list={posts.map(post => {
                        delete require.cache['posts/' + post];
                        return { ...require('./posts/' + post), key: post.replace('.json', '') };
                    })}
                />
            )}</div>`
        );
    } else {
        delete require.cache['posts/' + name];
        const postInfo = require('./posts/' + name);
        const fileName = `dist/posts/${name}.html`;
        await fs.writeFile(fileName, `<div id="root">${renderToString(<Post data={postInfo} />)}</div>`);
    }
}
export default build;

这样就可以通过 build 函数来构建指定的 post 或者 list 页面。

然后再将原先的构建脚本做一下简单的修改:

import fs from 'fs';
import build from './build-util';
// make sure the dir exists
if (!fs.existsSync('dist')) {
    fs.mkdirSync('dist');
}
if (!fs.existsSync('dist/posts')) {
    fs.mkdirSync('dist/posts');
}
// get all the files in posts
const posts = fs.readdirSync('posts');
(async () => {
    for await (const post of posts) {
        await build('post', post.replace('.json', ''));
    }
    await build('list');
})();

服务器

由于 ISR 需要在请求时做是否构建的判定,所以原先的静态服务器方案无法继续使用,我们换成 express 来实现:

import express from 'express';
import path from 'path';
import fs from 'fs';
import build from '../build-util';
const app = express();
const expiresTime = 1000 * 60 * 10;
app.use(function (req, res, next) {
    setTimeout(() => {
        const filename = req.path.indexOf('.html') >= 0 ? req.path : req.path + 'index.html';
        // get the file's create timestamps
        fs.stat(path.join('./dist', filename), function (err, stats) {
            if (err) {
                console.error(err);
                return;
            }
            if (Date.now() - +stats.mtime > expiresTime) {
                console.log(filename, 'files expired, rebuilding...');
                if (filename === '/index.html') {
                    build('list');
                } else {
                    build('post', path.basename(filename).replace('.html', ''));
                }
            }
        });
    });
    next();
});
app.use(express.static('dist'));
app.listen(4000, () => {
    console.log('Listening on port 4000');
});

我们增加一个 express 的中间件,让其来判定文件是否过期,这里以十分钟为例,实际场景可按需定义过期判定。这里过期后就会调用 build 文件来重新构建该文件。要注意此处先返回再构建,所以用户不会等待构建,并且此次访问依旧是旧的内容,构建完成后访问的才是新的内容。

更多细节

  • 注意给构建任务加锁,避免一个页面过期后多个请求同时触发多个同样的构建任务
  • 给构建任务加队列,避免请求过多时同时出现过多的后台构建任务导致服务器资源问题
  • 可以为每个文件制定特定的过期判定条件,比如 post 源文件的修改时间等等

总结

ISR 对比 SSG 可以有效的控制页面的时效性,但也要付出额外的代价:

  • 需要额外的开发成本
  • 需要额外的服务器资源投入
  • 无法使用一般的静态文件服务器

没有最佳,只有最适合,所以实际场景下还是按需选用。

本文的 demo 代码放置在 React ISR Demo 中,可自行取阅。

以上就是详解React ISR如何实现 Demo的详细内容,更多关于React ISR实现的资料请关注脚本之家其它相关文章!

相关文章

  • React Native模块之Permissions权限申请的实例相机

    React Native模块之Permissions权限申请的实例相机

    这篇文章主要介绍了React Native模块之Permissions权限申请的实例相机的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-09-09
  • React使用有限状态机的实现示例

    React使用有限状态机的实现示例

    本文主要介绍了React使用有限状态机的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • React Native使用fetch实现图片上传的示例代码

    React Native使用fetch实现图片上传的示例代码

    本篇文章主要介绍了React Native使用fetch实现图片上传的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • React Navigation 路由传参的操作代码

    React Navigation 路由传参的操作代码

    这篇文章主要介绍了React Navigation 路由传参,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • 教你在react中创建自定义hooks

    教你在react中创建自定义hooks

    简单来说就是使用自定义hook可以将某些组件逻辑提取到可重用的函数中。 自定义hook是一个从use开始的调用其他hook的Javascript函数,下面看下react中创建自定义hooks的相关知识,感兴趣的朋友一起看看吧
    2021-11-11
  • 高性能React开发React Server Components详解

    高性能React开发React Server Components详解

    ReactServerComponents通过服务器端渲染、自动代码分割等技术,实现了高性能的React开发,它解决了客户端数据请求链式延迟、敏感数据暴露风险等问题,提供了更好的用户体验和安全性,本文介绍高性能React开发React Server Components详解,感兴趣的朋友一起看看吧
    2025-03-03
  • React UI组件库之快速实现antd的按需引入和自定义主题

    React UI组件库之快速实现antd的按需引入和自定义主题

    react入门学习告一段路,下面这篇文章主要给大家介绍了关于React UI组件库之快速实现antd的按需引入和自定义主题的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • ahooks控制时机的hook实现方法

    ahooks控制时机的hook实现方法

    这篇文章主要为大家介绍了ahooks控制时机的hook实现方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • 使用react-router4.0实现重定向和404功能的方法

    使用react-router4.0实现重定向和404功能的方法

    本篇文章主要介绍了使用react-router4.0实现重定向和404功能的方法,具有一定的参考价值,有兴趣的可以了解一下
    2017-08-08
  • next-redux-wrapper使用细节及源码分析

    next-redux-wrapper使用细节及源码分析

    这篇文章主要为大家介绍了next-redux-wrapper使用细节及源码分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02

最新评论