RenderController

75 阅读1分钟

记录

import { useLayoutEffect, useState } from "react";

type RenderQueue = Array<{ component: React.ReactNode; preority: number }>;

const proxyHandler: ProxyHandler<RenderQueue> = {
  get: function (target, propKey) {
    if (propKey === "push") {
      return function (...args: RenderQueue) {
        const result = target.push.apply(target, args);
        target.sort((a, b) => a.preority - b.preority);
        return result;
      };
    } else {
      return target[propKey as any];
    }
  },
};

const RenderController: React.FC<{
  component: React.ReactNode;
  renderNextComponent: () => void;
}> = ({ component, renderNextComponent }) => {
  useLayoutEffect(() => {
    renderNextComponent();
  }, []);

  return <>{component}</>;
};

export const createRenderControllerHOC = () => {
  const renderQueue = new Proxy([], proxyHandler);

  const getHigestPreorityComp = () => {
    return renderQueue.shift();
  };

  const RenderControllerHOC = ({
    component,
    preority,
    fallback
  }: {
    component: React.ReactNode;
    preority: number;
    fallback: React.ReactNode;
  }) => {
    const [renderComp, updateRenderComp] = useState<React.ReactNode>();

    const renderNextComponent = () => {
      const nextComp = getHigestPreorityComp();
      updateRenderComp(nextComp?.component);
    };

    renderQueue.push({ component, preority });
    return (
      <RenderController
        component={renderComp}
        renderNextComponent={renderNextComponent}
      />
    );
  };

  return RenderControllerHOC;
};

目前会破坏dom,渲染出来的结果和tsx写的时候不一致。 考虑后续通过fallback先去进行占位,渲染的时候替换掉fallback,实现待定