From 690c84236bf8b8b2a7be83bf25814bdd15029dd3 Mon Sep 17 00:00:00 2001 From: Robby6Strings Date: Thu, 26 Sep 2024 04:58:08 +1200 Subject: [PATCH] lib - initial implementation of "lazy" components --- packages/lib/src/dom.ts | 2 +- packages/lib/src/index.ts | 1 + packages/lib/src/lazy.ts | 35 +++++++++++++++++++++++++ sandbox/csr/src/App.tsx | 9 ++++--- sandbox/csr/src/components/Counter.tsx | 4 ++- sandbox/csr/src/components/LazyDemo.tsx | 26 ++++++++++++++++++ 6 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 packages/lib/src/lazy.ts create mode 100644 sandbox/csr/src/components/LazyDemo.tsx diff --git a/packages/lib/src/dom.ts b/packages/lib/src/dom.ts index fdb10262..098a32bc 100644 --- a/packages/lib/src/dom.ts +++ b/packages/lib/src/dom.ts @@ -337,7 +337,7 @@ function placeDom( const n = stack.pop()! const _isPortal = isPortal(n) if (n.dom === dom) break // once we meet the dom we're placing, stop - if (!_isPortal && n.dom) prevDom = n.dom + if (!_isPortal && n.dom?.isConnected) prevDom = n.dom if (n.sibling) stack.push(n.sibling) if (!_isPortal && !n.dom && n.child) stack.push(n.child) } diff --git a/packages/lib/src/index.ts b/packages/lib/src/index.ts index 501b7417..643b0349 100644 --- a/packages/lib/src/index.ts +++ b/packages/lib/src/index.ts @@ -8,6 +8,7 @@ export * from "./context.js" export * from "./cloneVNode.js" export * from "./element.js" export * from "./hooks/index.js" +export * from "./lazy.js" export * from "./memo.js" export * from "./portal.js" export * from "./renderToString.js" diff --git a/packages/lib/src/lazy.ts b/packages/lib/src/lazy.ts new file mode 100644 index 00000000..ce1e5e74 --- /dev/null +++ b/packages/lib/src/lazy.ts @@ -0,0 +1,35 @@ +import { createElement } from "./element.js" +import { useRequestUpdate } from "./hooks/utils.js" + +const lazyCache = new WeakMap<() => Promise, Kaioken.FC | null>() + +type LazyComponentProps = Kaioken.InferProps & { + fallback?: JSX.Element +} + +export function lazy( + componentPromise: () => Promise +): Kaioken.FC> { + function LazyComponent(props: LazyComponentProps) { + const { fallback = null, ...rest } = props + const requestUpdate = useRequestUpdate() + if (!lazyCache.has(componentPromise)) { + lazyCache.set(componentPromise, null) + componentPromise().then((component) => { + lazyCache.set(componentPromise, component) + requestUpdate() + }) + return fallback + } + + const component: Kaioken.FC> | null = + lazyCache.get(componentPromise)! + if (component === null) { + componentPromise().then(requestUpdate) + return fallback + } + return createElement(component, rest) + } + LazyComponent.displayName = "Kaioken.lazy" + return LazyComponent +} diff --git a/sandbox/csr/src/App.tsx b/sandbox/csr/src/App.tsx index 1f917863..f177b618 100644 --- a/sandbox/csr/src/App.tsx +++ b/sandbox/csr/src/App.tsx @@ -1,6 +1,6 @@ import { Router, Route, useRouter, useState } from "kaioken" import { Todos } from "./components/ToDos" -import { Counter } from "./components/Counter" +//import { Counter } from "./components/Counter" import { ProductPage } from "./components/Product" import { Link } from "./components/atoms/Link" import { GithubIcon } from "./components/GithubIcon" @@ -16,6 +16,7 @@ import { UseSyncExternalStoreExample } from "./components/UseSyncExternalStoreEx import { UseModelExample } from "./components/useModelExample" import { GlobalComputedExample } from "./components/ComputedExample" import { LocalComputedExample } from "./components/ComputedExample" +import { LazyDemo } from "./components/LazyDemo" function Home() { return

Home

@@ -26,10 +27,11 @@ function Nav() {