Host.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import {
  2. type ReactNode,
  3. createContext,
  4. useEffect,
  5. useRef
  6. } from "react";
  7. import {
  8. type ViewStyle,
  9. View
  10. } from "react-native";
  11. import {
  12. useKey
  13. } from "./hooks/useKey";
  14. import {
  15. type IManagerHandles,
  16. Manager
  17. } from "./Manager";
  18. import {
  19. context
  20. } from "./context";
  21. interface IHostProps {
  22. children: ReactNode;
  23. style?: ViewStyle;
  24. name?: string;
  25. }
  26. export interface IProvider {
  27. update(key?: string, children?: ReactNode, name?: string): void;
  28. mount(children: ReactNode, name?: string): string;
  29. unmount(key?: string): void;
  30. name?: string;
  31. }
  32. export const Context = createContext<IProvider | null>(null);
  33. export const Host = ({
  34. children,
  35. style,
  36. name
  37. }: IHostProps): ReactNode => {
  38. const managerRef = useRef<IManagerHandles>(null);
  39. const queue: Array<{
  40. type: "mount" | "update" | "unmount";
  41. children?: ReactNode;
  42. name?: string;
  43. key: string;
  44. }> = [];
  45. const {
  46. generateKey,
  47. removeKey
  48. } = useKey();
  49. useEffect(() => {
  50. while (queue.length && managerRef.current) {
  51. const action = queue.pop();
  52. if (action) {
  53. switch (action.type) {
  54. case "mount":
  55. managerRef.current?.mount(action.key, action.children, action.name);
  56. break;
  57. case "update":
  58. managerRef.current?.update(action.key, action.children, action.name);
  59. break;
  60. case "unmount":
  61. managerRef.current?.unmount(action.key);
  62. break;
  63. }
  64. }
  65. }
  66. }, []);
  67. const mount = (children: ReactNode, _name?: string): string => {
  68. const key = generateKey();
  69. const targetName = _name ?? name;
  70. context.mount(key, children, targetName);
  71. return key;
  72. };
  73. const update = (key: string, children: ReactNode, _name?: string): void => {
  74. const targetName = _name ?? name;
  75. context.update(key, children, targetName);
  76. };
  77. const unmount = (key: string): void => {
  78. context.unmount(key);
  79. removeKey(key);
  80. };
  81. return <Context.Provider value={{
  82. unmount,
  83. update,
  84. mount,
  85. name
  86. }}>
  87. <View
  88. collapsable={false}
  89. style={[
  90. {
  91. pointerEvents: "box-none",
  92. flex: 1
  93. },
  94. style
  95. ]}
  96. >
  97. {children}
  98. </View>
  99. <Manager
  100. ref={managerRef}
  101. name={name}
  102. />
  103. </Context.Provider>;
  104. };