Jacky's blog Jacky's blog
首页
  • 编码专题
  • 深入浅出 Vite
  • 深入浅出 babel
  • 快速上手API
  • 深入浅出 react
  • Node

    • code-notebook
  • 状态管理

    • redux
  • 前端工程化

    • Wepack
  • React源码

    • React源码
  • 组件库封装

    • 组件库
  • 开发工具

    • Vscode 插件
  • 项目展示
  • 案例中心 (opens new window)
  • First Project
  • 基础算法题
  • 链表题
  • 动态规划
  • 双指针
  • 递归
  • 数据结构
  • 前端学习计划 (opens new window)
  • 技术随笔
  • 转载文章
  • 包管理工具
  • 前端学习周报
  • VSCode插件
  • Promise 专题
  • 函数技巧
  • React 专题
  • 配置文件

    • TSCONFIG-配置 (opens new window)
    • NGINX-配置 (opens new window)
    • 正则规则查询手册 (opens new window)
    • Lint 配置 (opens new window)
  • 教程

    • GIT-教程
    • NPM SCRIPTS-工作流 (opens new window)
    • DOCKER-教程 (opens new window)
    • LERNA-教程 (opens new window)
    • GIT-常用操作整理 (opens new window)
  • VSCode

    • LAUNCH.JSON (opens new window)
  • 指令

    • NPM 指令 (opens new window)
    • NVM 指令 (opens new window)
    • Nginx 指令 (opens new window)
    • YARN 指令 (opens new window)
    • PNPM 指令 (opens new window)
  • 库

    • FS-EXTRA 库 (opens new window)
    • NODE 库-PATH (opens new window)
  • 永远的神

    • 魔法师卡颂-自顶向下学 React 源码 (opens new window)
    • 全栈潇晨 (opens new window)
    • 博客-程序员山月-Daily (opens new window)
    • 淘系前端:冴羽 (opens new window)
  • 系列文章

    • 《图解HTTP》 (opens new window)
    • 《ES6标准入门》 (opens new window)
    • 《现代JavaScript教程》 (opens new window)
    • 《深入浅出Webpack》 (opens new window)
    • VSCode 插件系列:小茗同学 (opens new window)
    • JEST 教程 (opens new window)
    • 前端精读周刊:各种精读系列 (opens new window)
    • 一文吃透系列 (opens new window)
    • 图解 REACT 原理 (opens new window)
  • 实用网站

    • MDN (opens new window)
    • CAN I USE (opens new window)
    • TYPESCRIPT-ESLint-RULES (opens new window)
    • ESLint-RULES (opens new window)
    • FRONT-END TREND (opens new window)
    • NPM TREND (opens new window)
    • 在线分析 Node 依赖 (opens new window)
    • FIND NPM (opens new window)
    • CODE PEN (opens new window)
    • 印记中文 (opens new window)
    • TOOL.LU (opens new window)
    • 阮一峰-网道 (opens new window)
    • DIGITAL OCEAN (opens new window)
    • DEVDOCS.IO (opens new window)
    • JOI (opens new window)
  • 算法

    • 小浩算法 (opens new window)
    • LABULADONG 的算法小抄 (opens new window)
    • 力扣 SOLUTION (opens new window)
    • HACKER RANK (opens new window)
    • 代码随想录 (opens new window)
  • 博客系列

    • 美团大佬 (opens new window)
    • 蜡笔小伟 (opens new window)
    • 优秀博客1 (opens new window)
    • 优秀博客2-umi (opens new window)
    • 优质博客 (opens new window)
  • CSS

    • CSS-EASING 库 (opens new window)
    • ROUGH.JS (opens new window)
    • CSS 网站收集
    • UNOCSS (opens new window)
  • 前端

    • PROMISE (opens new window)
    • UNDERSCORE.JS (opens new window)
    • study with BGM (opens new window)
    • nginx【B站视频】 (opens new window)
    • 机器学习
    • Js基础
  • 掘金已购课程

    • 前端自动化测试精讲 (opens new window)
    • 深入浅出 Vite (opens new window)
    • 现代 Web 布局 (opens new window)
    • 前端算法与数据结构 (opens new window)
    • 基于 Vite 的 SSG 框架开发实战 (opens new window)
    • SSR 实战:官网开发指南 (opens new window)
    • WebGL 入门与实践 (opens new window)
    • 玩转 CSS 的艺术之美 (opens new window)
    • 前端调试通关秘籍 (opens new window)
    • React 进阶实践指南 (opens new window)
    • TypeScript 全面进阶指南 (opens new window)
    • 前端缓存技术与方案解析 (opens new window)
    • npm scripts 前端工作流 (opens new window)
    • Webpack5 核心原理与应用实践 (opens new window)
  • 购物车

    • 张鑫旭-技术写作指南 (opens new window)
    • 深入剖析 Node.js 底层原理 (opens new window)
    • 前端开发者的现代 C++ 课 (opens new window)
    • 从前端到全栈 (opens new window)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Jacky Wang

行到水穷处,坐看云起时
首页
  • 编码专题
  • 深入浅出 Vite
  • 深入浅出 babel
  • 快速上手API
  • 深入浅出 react
  • Node

    • code-notebook
  • 状态管理

    • redux
  • 前端工程化

    • Wepack
  • React源码

    • React源码
  • 组件库封装

    • 组件库
  • 开发工具

    • Vscode 插件
  • 项目展示
  • 案例中心 (opens new window)
  • First Project
  • 基础算法题
  • 链表题
  • 动态规划
  • 双指针
  • 递归
  • 数据结构
  • 前端学习计划 (opens new window)
  • 技术随笔
  • 转载文章
  • 包管理工具
  • 前端学习周报
  • VSCode插件
  • Promise 专题
  • 函数技巧
  • React 专题
  • 配置文件

    • TSCONFIG-配置 (opens new window)
    • NGINX-配置 (opens new window)
    • 正则规则查询手册 (opens new window)
    • Lint 配置 (opens new window)
  • 教程

    • GIT-教程
    • NPM SCRIPTS-工作流 (opens new window)
    • DOCKER-教程 (opens new window)
    • LERNA-教程 (opens new window)
    • GIT-常用操作整理 (opens new window)
  • VSCode

    • LAUNCH.JSON (opens new window)
  • 指令

    • NPM 指令 (opens new window)
    • NVM 指令 (opens new window)
    • Nginx 指令 (opens new window)
    • YARN 指令 (opens new window)
    • PNPM 指令 (opens new window)
  • 库

    • FS-EXTRA 库 (opens new window)
    • NODE 库-PATH (opens new window)
  • 永远的神

    • 魔法师卡颂-自顶向下学 React 源码 (opens new window)
    • 全栈潇晨 (opens new window)
    • 博客-程序员山月-Daily (opens new window)
    • 淘系前端:冴羽 (opens new window)
  • 系列文章

    • 《图解HTTP》 (opens new window)
    • 《ES6标准入门》 (opens new window)
    • 《现代JavaScript教程》 (opens new window)
    • 《深入浅出Webpack》 (opens new window)
    • VSCode 插件系列:小茗同学 (opens new window)
    • JEST 教程 (opens new window)
    • 前端精读周刊:各种精读系列 (opens new window)
    • 一文吃透系列 (opens new window)
    • 图解 REACT 原理 (opens new window)
  • 实用网站

    • MDN (opens new window)
    • CAN I USE (opens new window)
    • TYPESCRIPT-ESLint-RULES (opens new window)
    • ESLint-RULES (opens new window)
    • FRONT-END TREND (opens new window)
    • NPM TREND (opens new window)
    • 在线分析 Node 依赖 (opens new window)
    • FIND NPM (opens new window)
    • CODE PEN (opens new window)
    • 印记中文 (opens new window)
    • TOOL.LU (opens new window)
    • 阮一峰-网道 (opens new window)
    • DIGITAL OCEAN (opens new window)
    • DEVDOCS.IO (opens new window)
    • JOI (opens new window)
  • 算法

    • 小浩算法 (opens new window)
    • LABULADONG 的算法小抄 (opens new window)
    • 力扣 SOLUTION (opens new window)
    • HACKER RANK (opens new window)
    • 代码随想录 (opens new window)
  • 博客系列

    • 美团大佬 (opens new window)
    • 蜡笔小伟 (opens new window)
    • 优秀博客1 (opens new window)
    • 优秀博客2-umi (opens new window)
    • 优质博客 (opens new window)
  • CSS

    • CSS-EASING 库 (opens new window)
    • ROUGH.JS (opens new window)
    • CSS 网站收集
    • UNOCSS (opens new window)
  • 前端

    • PROMISE (opens new window)
    • UNDERSCORE.JS (opens new window)
    • study with BGM (opens new window)
    • nginx【B站视频】 (opens new window)
    • 机器学习
    • Js基础
  • 掘金已购课程

    • 前端自动化测试精讲 (opens new window)
    • 深入浅出 Vite (opens new window)
    • 现代 Web 布局 (opens new window)
    • 前端算法与数据结构 (opens new window)
    • 基于 Vite 的 SSG 框架开发实战 (opens new window)
    • SSR 实战:官网开发指南 (opens new window)
    • WebGL 入门与实践 (opens new window)
    • 玩转 CSS 的艺术之美 (opens new window)
    • 前端调试通关秘籍 (opens new window)
    • React 进阶实践指南 (opens new window)
    • TypeScript 全面进阶指南 (opens new window)
    • 前端缓存技术与方案解析 (opens new window)
    • npm scripts 前端工作流 (opens new window)
    • Webpack5 核心原理与应用实践 (opens new window)
  • 购物车

    • 张鑫旭-技术写作指南 (opens new window)
    • 深入剖析 Node.js 底层原理 (opens new window)
    • 前端开发者的现代 C++ 课 (opens new window)
    • 从前端到全栈 (opens new window)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Node

  • VSCode插件

  • Webpack

  • Redux

  • React源码

  • 组件库

    • Dialog组件封装
    • 组件导入思考
    • Keepalive 伪代码
      • KeepaliveScope
      • 如何渲染 children?
      • ScopeItem
      • KeepaliveItem
    • React 组件:Loading 弹窗
  • React高阶系列

  • UMI插件

  • 前端工程化

  • 单元测试vitest

  • 重点技术
  • 组件库
wangjiasheng
2022-09-27
目录

Keepalive 伪代码

# KeepaliveScope

  • HOC经典应用,包裹一层 Context
const KeepaliveContext = React.createContext({})

function Scope({ children }) {
    /* 自定义 Hooks 分离出所需的 state */
    const keeper = useKeep()
    /* 很像 redux,使用 dispatch 去单向修改 state */
    const { state, dispatch } = keeper
    /* 重点:HOC children 的写法*/
    const renderChildren = children
    /* 包裹一层 Context,注意一定要使用 useMemo */  
    const contextValue = useMemo(() => {
        return {
          dispatch:dispatch
          yyy:yyyy
        }
    }, [keeper])
    return <KeepaliveContext.Provider value={contextValue}>
        {/* Scope 是 Function Component 的写法*/}
        {renderChildren}
        { /* 用一个列表渲染  */ }
        {cacheList.map(item => <ScopeItem {...item} dispatch={dispatch.bind(keeper)} key={item.cacheId} />)}
    </KeepaliveContext.Provider>
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

注意:当使用的是实例方法的,那在使用时需要 bind 下指针。

# 如何渲染 children?

  • 直接渲染

    直接渲染 children

  • 渲染时需要带上 props

    通过构造一个 renderWithChildren

# ScopeItem

通过 cacheList 做了一层渲染拦截的效果,渲染逻辑是:

原本由:KeepaliveItem 渲染的真实的 DOM ,缓存在 cacheList 的 children 上,交给 ScopeItem 去代替 KeepaliveItem 控制渲染。

步骤如下:

  1. 将原本的 children 通过 createPortal 渲染到 document.body 节点上,伪代码如下:

    注:此时应设置 display 为 none

    const children = cacheList.children
    const element = ReactDOM.createPortal(<div style={{display:"none"}}>{children}</div>,document.body)
    
    1
    2

    为了后续能控制这部分代码的渲染,所以还需要加上 ref

    const currentDOM = useRef();
    const element = ReactDOM.createPortal(<div ref={currentDOM} style={{display:"none"}}>{children}</div>,document.body)
    
    
    1
    2
    3
  2. cacheList 中还存放着当前组件的生命周期

    • 当处于 active 的状态时,则需要将 display 为 block 状态的 jsx 对象由 parenNode 去渲染。

      if(status === "active"){  
        cacheList.parentNode.appendChild(currentDOM.current)
      }
      
      1
      2
      3
    • 当组件从 active 状态变为 unactive 的状态时,则重新挂载到 body 上。

      if(status==="unactive"){
        document.body.appendChild(currentDOM.current)
      }
      
      1
      2
      3

      如果是封装组件库的话,其实还可以添加生命周期,如下:

      if(status==="unactive"){
        document.body.appendChild(currentDOM.current);
        fake_LifeCircle();
        /* 实际代码中是使用 Keepalive 去(事件发布订阅机制)去缓存状态的,如下:*/
      	dispatch({
          type: "unactived",
          payload: cacheId
        })
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
  3. 这里需要注意一个细节,将 DOM 结构完全摘出来以后,就无法做到与父元素渲染子元素也随着更新的这样一个状态(ps:感觉又有些像 Vue,响应式编程)

    解决方案:在 cacheList 存的时候多存一个标志位,用于模拟父组件的更新效果。

    即,让 created 以及 update 生命周期时,多保存一个 updater:{} 的状态,用于 forceUpdate 组件。

    改写,第一个步骤的代码:

    const element = ReactDOM.createPortal(
    <div style={{display:"none"}}>
     - {children}
     + {useMemo(()=> renderChildren(),[updater])} 
    </div>,document.body)
    
    1
    2
    3
    4
    5

    # KeepaliveItem

    使用方式:

    <KeepaliveItem cacheId="demo-xxx">
    	  <Child />
    </KeepaliveItem>
    
    1
    2
    3

    主要目的就是构造对象存入 cacheList 中,此时 cacheList 是保存在 keepaliveScope 中的,因此,只能使用 useContext 的方式去取修改方法,如:

    const {cacheDispatch} = useContext(keepaliveContext)
    
    1

    将 KeepaliveItem 中的生命周期,缓存到 cacheList 中

编辑 (opens new window)
上次更新: 2022/10/08, 23:10:00
组件导入思考
React 组件:Loading 弹窗

← 组件导入思考 React 组件:Loading 弹窗→

最近更新
01
如何理解浏览器的 user agent 用户代理的含义?
11-05
02
浏览器事件循环机制
10-31
03
浏览器页面渲染机制【2023】
10-15
更多文章>
Theme by Vdoing | Copyright © 2020-2023
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式