xref: /MusicFree/src/components/base/portal.tsx (revision e650bfb34226e2a09d15cbf7832c4805a87cd60e)
1*e650bfb3S猫头猫import React, {ReactNode, useEffect, useRef} from 'react';
2*e650bfb3S猫头猫import {StyleSheet, View} from 'react-native';
3*e650bfb3S猫头猫import {atom, useAtomValue, useSetAtom} from 'jotai';
4*e650bfb3S猫头猫
5*e650bfb3S猫头猫interface IPortalNode {
6*e650bfb3S猫头猫    key: string | null;
7*e650bfb3S猫头猫    children: ReactNode;
8*e650bfb3S猫头猫}
9*e650bfb3S猫头猫
10*e650bfb3S猫头猫const portalsAtom = atom<IPortalNode[]>([]);
11*e650bfb3S猫头猫
12*e650bfb3S猫头猫interface IPortalProps {
13*e650bfb3S猫头猫    children: ReactNode;
14*e650bfb3S猫头猫}
15*e650bfb3S猫头猫export default function Portal(props: IPortalProps) {
16*e650bfb3S猫头猫    const {children} = props;
17*e650bfb3S猫头猫
18*e650bfb3S猫头猫    const keyRef = useRef<string | null>(null);
19*e650bfb3S猫头猫    const setPortalsAtoms = useSetAtom(portalsAtom);
20*e650bfb3S猫头猫
21*e650bfb3S猫头猫    useEffect(() => {
22*e650bfb3S猫头猫        if (!keyRef.current) {
23*e650bfb3S猫头猫            // mount
24*e650bfb3S猫头猫            keyRef.current = Math.random().toString().slice(2);
25*e650bfb3S猫头猫            // console.log("MOUNT!", keyRef.current);
26*e650bfb3S猫头猫            setPortalsAtoms(portals => [
27*e650bfb3S猫头猫                ...portals,
28*e650bfb3S猫头猫                {key: keyRef.current, children},
29*e650bfb3S猫头猫            ]);
30*e650bfb3S猫头猫        } else {
31*e650bfb3S猫头猫            // update
32*e650bfb3S猫头猫            // console.log("UPDATE!", keyRef.current);
33*e650bfb3S猫头猫            setPortalsAtoms(portals =>
34*e650bfb3S猫头猫                portals.map(it =>
35*e650bfb3S猫头猫                    it.key === keyRef.current ? {...it, children} : it,
36*e650bfb3S猫头猫                ),
37*e650bfb3S猫头猫            );
38*e650bfb3S猫头猫        }
39*e650bfb3S猫头猫    }, [children]);
40*e650bfb3S猫头猫
41*e650bfb3S猫头猫    useEffect(() => {
42*e650bfb3S猫头猫        return () => {
43*e650bfb3S猫头猫            if (keyRef.current) {
44*e650bfb3S猫头猫                // console.log("UNMOUNT!", keyRef.current);
45*e650bfb3S猫头猫                setPortalsAtoms(portals =>
46*e650bfb3S猫头猫                    portals.filter(it => it.key !== keyRef.current),
47*e650bfb3S猫头猫                );
48*e650bfb3S猫头猫            }
49*e650bfb3S猫头猫        };
50*e650bfb3S猫头猫    }, []);
51*e650bfb3S猫头猫
52*e650bfb3S猫头猫    return null;
53*e650bfb3S猫头猫}
54*e650bfb3S猫头猫
55*e650bfb3S猫头猫export function PortalHost() {
56*e650bfb3S猫头猫    const portals = useAtomValue(portalsAtom);
57*e650bfb3S猫头猫
58*e650bfb3S猫头猫    return (
59*e650bfb3S猫头猫        <>
60*e650bfb3S猫头猫            {portals.map(({key, children}) => (
61*e650bfb3S猫头猫                <View
62*e650bfb3S猫头猫                    key={key}
63*e650bfb3S猫头猫                    collapsable={false}
64*e650bfb3S猫头猫                    pointerEvents="box-none"
65*e650bfb3S猫头猫                    style={StyleSheet.absoluteFill}>
66*e650bfb3S猫头猫                    {children}
67*e650bfb3S猫头猫                </View>
68*e650bfb3S猫头猫            ))}
69*e650bfb3S猫头猫        </>
70*e650bfb3S猫头猫    );
71*e650bfb3S猫头猫}
72