Skip to content

v1.0.0

Compare
Choose a tag to compare
@localvoid localvoid released this 03 Apr 09:42
· 385 commits to master since this release

Components

Added second prop to components.

const Button = statelessComponent<{ id: string }, Op>((props, children) => (
  button("button", props, children)
));

Button({ id: "button-id" },
  "Click Me",
);

Custom areEqual function

const View = statelessComponent<number, [number, number]>(
  (a, b) => (
    a + b[0] + b[1]
  ),
  undefined,
  shallowEqualArray,
);
View(1, [2, 3]);

Dirty Checking / Observables

Dirty checking API were redesigned to improve support for use cases with coarse-grained observable graphs and
mutable data structures.

New API for dirty checking is composable and can be used in stateless components.

  • useSelect() hook were removed.
  • Added pull-based observables.
  • Context is reimplemented with observables and it is now way much cheaper to dirty check.

Examples

Computed Values (lazy evaluation)
const a = observable(1);
const b = observable(2);
const sum = computed(() => watch(a) + watch(b));
const A = statelessComponent(() => div(_, _, watch(sum)()));
Basic selectors with immutable state
const STATE = { value: 1 };
const A = component((c) => {
  const getValue = selector(() => STATE.value);
  return () => div(_, _, watch(getValue)());
});
Memoized selector with immutable state
const STATE = { a: 1, b: 2 };
const A = component((c) => {
  const getValue = selector((prev) => (
    prev !== void 0 && prev.a === STATE.a && prev.b === STATE.b ? prev :
      { a: STATE.a, b: STATE.b, result: STATE.a + STATE.b };
  ));
  return () => div(_, _, watch(getValue)());
});
Composition
const a = observable(1);
const A = component((c) => {
  const getValue = memo((i) => computed(() => watch(a) + i));
  return (i) => div(_, _, watch(getValue(i))());
});

Boolean DOM Attribute Values

Removed automagic conversion from boolean values to empty string. Correct attribute values should be specified
explicitly.

textContent="" Optimization

This optimization has a quite noticeable impact in popular benchmarks. But in real applications, use cases that would benefit from this optimization will work significantly faster by wrapping lists into a transient DOM node.

Deep State Tracking

Deep state tracking optimization were removed. It is one of those optimizations that improve performance in benchmarks, but make it worse in real applications.

This optimization worked by updating node state flags during stack unwinding. It saved information about node subtree, so we could skip dirty checking and unmounting for subtrees that didn't have any stateful components. In applications decomposed into small components there will be many stateful components used as leaf nodes, so instead of optimizing, it will make dirty checking and reconciliation algorithms slightly slower. Also, this optimization were adding a lot of complexity to the reconciliation algorithm.

Simplified track by key algorithm

Instead of returning LIS indices, nodes that are part of LIS are now marked in the input array.

Events

Stop Propagation

Synthetic event handlers do not propagate events anymore. To propagate events, event handler should return
DispatchEvent.Propagate value.

Move Events

Removed touch/mouse/pointer move events. Move event handlers usually attached when down event is triggered. To make sure that we don't lose any move events, we can't wait until next frame is rerendered, so move event handlers should be attached with native DOM api.

Server Side Rendering

Removed. Not interested in supporting this feature.