solid icon indicating copy to clipboard operation
solid copied to clipboard

Hope to provide Keepalive component

Open yibird opened this issue 1 year ago • 3 comments

Describe the bug

Hope to provide Keepalive component

Your Example Website or App

Hope to provide Keepalive component

Steps to Reproduce the Bug or Issue

Hope to provide Keepalive component

Expected behavior

Hope to provide Keepalive component

Screenshots or Videos

Hope to provide Keepalive component

Platform

  • OS: [e.g. macOS, Windows, Linux]
  • Browser: [e.g. Chrome, Safari, Firefox]
  • Version: [e.g. 91.1] Hope to provide Keepalive component

Additional context

Hope to provide Keepalive component

yibird avatar Dec 06 '24 19:12 yibird

I've been waiting for this feature for two years. You can check it out here: solid-router issue #204.

Currently, I'm using solid-keep-alive as an alternative.

ahzvenol avatar Dec 07 '24 08:12 ahzvenol

Yes, in fact, you may not need an API like vue. This is a keep-alive function I implemented. It works well and meets all scenarios. Toggle is a substitute for Show.

export default function createKeepAlive() {
  const owner = getOwner();
  let cache:
    | {
        depose(): void;
        el: JSX.Element;
      }
    | undefined = undefined;
  function render(
    el: () => JSX.Element,
    active: Accessor<boolean> = () => true
  ) {
    if (!cache) {
      cache = createRoot((depose) => {
        return {
          el: <ActiveProvider value={active()} children={el()} />,
          depose,
        };
      }, owner);
    }
    return cache.el;
  }
  onCleanup(() => {
    cache && cache.depose();
  });

  return render;
}


export function Toggle<T>(props: ToggleProps<T>) {
  let render: RenderType = (el) => el();
  let renderFallback = render;
  if (props.keepAlive !== false) {
    render = createKeepAlive();
    renderFallback = createKeepAlive();
  }
  const when = createMemo(() => Boolean(props.when));

  return (
    <Show
      when={when()}
      fallback={renderFallback(
        () => props.fallback,
        () => !when()
      )}
    >
      {render(
        () => props.children,
        () => when()
      )}
    </Show>
  );
}

export interface ToggleProps<T> {
  when: T | undefined | null | false;
  fallback?: JSX.Element;
  children: JSX.Element;
  keepAlive?: boolean;
}

type RenderType = (
  el: () => JSX.Element,
  active: Accessor<boolean>
) => JSX.Element;

You can also use object pool technology to cache loops, but these two are different concepts. Although vue is simple, it is actually very confusing. Each is a substitute for For.

import { createRootPool } from '@solid-primitives/rootless';
import { For, JSX } from 'solid-js';
import { useActiveMemo } from './Active';


export default function Each<T extends readonly any[]>(props: {
  each: T | undefined | null | false;
  fallback?: JSX.Element;
  component: (props: { data: T[number]; active?: boolean }) => JSX.Element;
  limit?: number;
}) {
  const activeEach = useActiveMemo(() => props.each);
  const pool = createRootPool<T[number], JSX.Element>(
    (it, active) => {
      const el = props.component({
        get data() {
          return it();
        },
        get active() {
          return active();
        },
      });
      return el;
    },
    { limit: props.limit || 100 }
  );

  return (
    <For each={activeEach()} fallback={props.fallback}>
      {(it) => pool(it)}
    </For>
  );
}

hex0xf avatar Jan 15 '25 02:01 hex0xf

@hex0xf Although your approach can achieve functionality, it lacks cache eviction strategies (which can easily lead to memory leaks) and some advanced features.

yibird avatar Aug 28 '25 13:08 yibird