image

React

12 January 2026


Trick

ElementRef

const { audioRef } = usePlayerContext();
 
const [_hasAudio, setHasAudio] = useState(false);
 
useEffect(() => {
  setHasAudio(true);
}, []);
 
return (
  <>
    <audio ref={audioRef} className="hidden" />
 
    {audioRef.current && (
      <PlayerEffect audioEle={audioRef.current}>
        {isOnMobile ? mobileContent : desktopContent}
      </PlayerEffect>
    )}
  </>
);
export default function PlayerEffect({ children, audioEle }: Props) {
  const { isOnMobile } = useThemeContext();
 
  usePlayerEffect();
  useCountDown();
  useIdle(appConfig.focusDelay, isOnMobile);
  usePlayCount({ audioEle });
 
  return useMemo(() => children, []);
}
 

Handle auto remove toast

  const { setToasts, toasts } = useToastContext();
  const [removing, setRemoving] = useState("");
 
  const removeToast = (id: string) => {
    setToasts((t) => t.filter((toast) => toast.id != id));
  };
 
  useEffect(() => {
    if (removing) setToasts((t) => t.filter((toast) => toast.id != removing));
  }, [removing]);
 
  useEffect(() => {
    if (!toasts.length) return;
 
    const id = toasts[toasts.length - 1].id;
    setTimeout(() => setRemoving(id), time);
  }, [toasts]);

Exposing methods to global ref

const { controlRef } = usePlayerContext();
 
useImperativeHandle(controlRef, () => ({
  pause,
  play,
  handlePlayPause,
}));

Type from string array

const tabs = ["Favorite", "Own"] as const;
type Tab = (typeof tabs)[number];

Init fetch

const [tab, setTab] = useState<Tab | "">("");
 
useEffect(() => {
  const initRun = async () => {
    const lastTab = getLocalStorage()["last_playlist_tab"] as Tab;
 
    await getPlaylist(lastTab);
    setTab(lastTab || 'Favorite');
  };
 
  if (!ranEffect.current) {
    ranEffect.current = true;
    initRun();
  }
});
 
useEffect(() => {
  if (!tab) return;
 
  getPlaylist();
}, [tab]);

Get item by slug

  const params = useParams<{id: string}>();
  routeSlug = "/playlist/:id"

Make withby Nguyen Huu Dat

© 2025