Host.tsx 2.8 KB

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