Skip to content

Improvement: Unit of work for "observable" #1

@betula

Description

@betula
import { autorun } from 'mobx';
import { FunctionComponent, memo, NamedExoticComponent, useRef, useState } from 'react';

type State = {
  scheduled?: boolean;
  unsubscriber?: () => void;
};

export function observer<T extends object>(Comp: FunctionComponent<T>): NamedExoticComponent<T>;
export function observer<T extends object>(
  Comp: FunctionComponent<T>,
  options: { forwardRef: true },
): FunctionComponent<T>;
export function observer<T extends object>(
  Comp: FunctionComponent<T>,
  options?: { forwardRef: boolean },
): FunctionComponent<T> | NamedExoticComponent<T> {
  return options?.forwardRef ? ObserveInner : (memo(ObserveInner) as unknown as NamedExoticComponent<T>);

  function ObserveInner(this: unknown, props: T, contextOrForwardedRef?: unknown) {
    const [_, forceUpdate] = useState<object>();
    const stateRef = useRef<State>();

    if (!stateRef.current) {
      stateRef.current = {};
    }
    const state = stateRef.current;

    if (state.unsubscriber) {
      state.unsubscriber();
    }
    let runned = false;
    let ret;
    state.unsubscriber = autorun(() => {
      if (runned) {
        if (!state.scheduled) {
          state.scheduled = true;
          queueMicrotask(() => {
            state.scheduled = false;
            forceUpdate({});
          });
        }
      } else {
        runned = true;
        ret = Comp.call(this, props, contextOrForwardedRef);
      }
    });

    return ret;
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions