localvoid / ivi

Lighweight Embeddable Web UI Library
MIT License
723 stars 22 forks source link

is there a way to memo pure / stateless components? #59

Open leeoniya opened 1 year ago

leeoniya commented 1 year ago

hey @localvoid, it's me again :D

something like React.memo?

e.g. i have this:

import { htm as html } from "@ivi/htm";

export const Button = (text: string, onclick: () => void) => html`
  <button @click=${onclick}>${text}</button>
`;

i would like to specify a static Button.areEqual comparator function to short-circuit the rendering, or something like

import { memo, shallowEqArray } from "ivi";
import { htm as html } from "@ivi/htm";

export const Button = memo((text: string, onclick: () => void) => html`
  <button @click=${onclick}>${text}</button>
`, shallowEqArray);

where shallowEqArray would take prevArgs and nextArgs.

i can implement memo in userland of course, but feels like ivi should offer it.

EDIT: maybe i can't implement it in userland, because the args/result needs to be memoized for each specific vtree location, so that stuff like [Button("foo"), Button("bar")] still works correctly. or there needs to be some deterministic cache eviction strategy if it's just a generic memoization wrapper :thinking: . e.g. not sure how https://github.com/caiogondim/fast-memoize.js deals with cache clearing.

localvoid commented 1 year ago

With ivi 3.0 I've decided to keep it simple and use the same component() API for stateless components.

import { component, shallowEqArray } from "ivi";
import { htm as html } from "@ivi/htm";

export const Button = component(() => ([text: string, onclick: () => void]) => html`
  <button @click=${onclick}>${text}</button>
`, shallowEqArray);

Internal render function can be hoisted to reduce memory usage (it should be quite easy to implement as a babel plugin, so that it can automatically detect stateless components and hoist internal render functions):

import { component, shallowEqArray } from "ivi";
import { htm as html } from "@ivi/htm";

const _inner = ([text: string, onclick: () => void]) => html`
  <button @click=${onclick}>${text}</button>
`;
export const Button = component(() => _inner, shallowEqArray);
leeoniya commented 1 year ago

Internal render function can be hoisted to reduce memory usage

that would be cool :) also #60 ;)