diff --git a/src/hooks/useCart.ts b/src/hooks/useCart.ts index 7448e7b..1b71e5b 100644 --- a/src/hooks/useCart.ts +++ b/src/hooks/useCart.ts @@ -1,4 +1,4 @@ -import { useEffect, useRef } from "react"; +import { useEffect, useLayoutEffect, useRef } from "react"; import { isAxiosError } from "axios"; import { devlog } from "../utils"; import { addCartTariffs, removeMissingCartTariffs, setCartTariffStatus, useCartStore } from "../stores/cart"; @@ -15,7 +15,7 @@ export function useCart({ tariffs, tariffIds, onTariffRemove }: { const cartTariffMap = useCartStore(state => state.cartTariffMap); const cart = useCartStore(state => state.cart); - useEffect(() => { + useLayoutEffect(() => { onTariffRemoveRef.current = onTariffRemove; }, [onTariffRemove]); diff --git a/src/hooks/useSSESubscription.ts b/src/hooks/useSSESubscription.ts index 9a55a2d..52f9602 100644 --- a/src/hooks/useSSESubscription.ts +++ b/src/hooks/useSSESubscription.ts @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { useEffect, useLayoutEffect, useRef } from "react"; import ReconnectingEventSource from "reconnecting-eventsource"; import { devlog } from "../utils"; @@ -10,6 +10,14 @@ export function useSSESubscription({ enabled = true, url, onNewData, onDiscon onDisconnect: () => void; marker?: string; }) { + const onNewDataRef = useRef(onNewData); + const onDisconnectRef = useRef(onDisconnect); + + useLayoutEffect(() => { + onNewDataRef.current = onNewData; + onDisconnectRef.current = onDisconnect; + }, [onNewData, onDisconnect]); + useEffect(() => { if (!enabled) return; @@ -21,7 +29,7 @@ export function useSSESubscription({ enabled = true, url, onNewData, onDiscon try { const newData = JSON.parse(event.data) as T; devlog(`new SSE: ${marker}`, newData); - onNewData([newData]); + onNewDataRef.current([newData]); } catch (error) { devlog(`SSE parsing error: ${marker}`, event.data, error); } @@ -32,7 +40,7 @@ export function useSSESubscription({ enabled = true, url, onNewData, onDiscon return () => { eventSource.close(); - onDisconnect(); + onDisconnectRef.current(); }; - }, [enabled, marker, onDisconnect, onNewData, url]); + }, [enabled, marker, url]); } \ No newline at end of file diff --git a/src/hooks/useTariffs.ts b/src/hooks/useTariffs.ts index c40b370..3d78321 100644 --- a/src/hooks/useTariffs.ts +++ b/src/hooks/useTariffs.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useLayoutEffect, useRef, useState } from "react"; import { makeRequest } from "../api"; import { Tariff, GetTariffsResponse } from "../model/tariff"; import { devlog } from "../utils"; @@ -12,6 +12,13 @@ export function useTariffs({ url, tariffsPerPage, apiPage, onNewTariffs, onError onError: (error: Error) => void; }) { const [fetchState, setFetchState] = useState<"fetching" | "idle" | "all fetched">("idle"); + const onNewTariffsRef = useRef(onNewTariffs); + const onErrorRef = useRef(onError); + + useLayoutEffect(() => { + onNewTariffsRef.current = onNewTariffs; + onErrorRef.current = onError; + }, [onNewTariffs, onError]); useEffect(function fetchTickets() { const controller = new AbortController(); @@ -25,16 +32,16 @@ export function useTariffs({ url, tariffsPerPage, apiPage, onNewTariffs, onError }).then((result) => { devlog("GetTariffsResponse", result); if (result.tariffs.length > 0) { - onNewTariffs(result.tariffs); + onNewTariffsRef.current(result.tariffs); setFetchState("idle"); } else setFetchState("all fetched"); }).catch(error => { devlog("Error fetching tariffs", error); - onError(error); + onErrorRef.current(error); }); return () => controller.abort(); - }, [onError, onNewTariffs, apiPage, tariffsPerPage, url]); + }, [apiPage, tariffsPerPage, url]); return fetchState; } \ No newline at end of file diff --git a/src/hooks/useTicketMessages.ts b/src/hooks/useTicketMessages.ts index 9bb6598..4c8f2ee 100644 --- a/src/hooks/useTicketMessages.ts +++ b/src/hooks/useTicketMessages.ts @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef, useLayoutEffect } from "react"; import { TicketMessage, GetMessagesRequest, GetMessagesResponse } from "../model"; import { devlog } from "../utils"; import { makeRequest } from "../api"; @@ -14,6 +14,13 @@ export function useTicketMessages({ url, messageApiPage, messagesPerPage, ticket isUnauth?: boolean; }) { const [fetchState, setFetchState] = useState<"fetching" | "idle" | "all fetched">("idle"); + const onNewMessagesRef = useRef(onNewMessages); + const onErrorRef = useRef(onError); + + useLayoutEffect(() => { + onNewMessagesRef.current = onNewMessages; + onErrorRef.current = onError; + }, [onNewMessages, onError]); useEffect(function fetchTicketMessages() { if (!ticketId) return; @@ -35,16 +42,16 @@ export function useTicketMessages({ url, messageApiPage, messagesPerPage, ticket }).then(result => { devlog("GetMessagesResponse", result); if (result?.length > 0) { - onNewMessages(result); + onNewMessagesRef.current(result); setFetchState("idle"); } else setFetchState("all fetched"); }).catch(error => { devlog("Error fetching messages", error); - onError(error); + onErrorRef.current(error); }); return () => controller.abort(); - }, [isUnauth, makeRequest, messageApiPage, messagesPerPage, onError, onNewMessages, ticketId, url]); + }, [isUnauth, messageApiPage, messagesPerPage, ticketId, url]); return fetchState; } \ No newline at end of file diff --git a/src/hooks/useTickets.ts b/src/hooks/useTickets.ts index 1f99036..bb3a8ac 100644 --- a/src/hooks/useTickets.ts +++ b/src/hooks/useTickets.ts @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef, useLayoutEffect } from "react"; import { GetTicketsResponse, GetTicketsRequest } from "../model"; import { devlog } from "../utils"; import { makeRequest } from "../api"; @@ -12,6 +12,13 @@ export function useTickets({ url, ticketsPerPage, ticketApiPage, onNewTickets, o onError: (error: Error) => void; }) { const [fetchState, setFetchState] = useState<"fetching" | "idle" | "all fetched">("idle"); + const onNewTicketsRef = useRef(onNewTickets); + const onErrorRef = useRef(onError); + + useLayoutEffect(() => { + onNewTicketsRef.current = onNewTickets; + onErrorRef.current = onError; + }, [onNewTickets, onError]); useEffect(function fetchTickets() { const controller = new AbortController(); @@ -30,16 +37,16 @@ export function useTickets({ url, ticketsPerPage, ticketApiPage, onNewTickets, o }).then((result) => { devlog("GetTicketsResponse", result); if (result.data) { - onNewTickets(result); + onNewTicketsRef.current(result); setFetchState("idle"); } else setFetchState("all fetched"); }).catch(error => { devlog("Error fetching tickets", error); - onError(error); + onErrorRef.current(error); }); return () => controller.abort(); - }, [makeRequest, onError, onNewTickets, ticketApiPage, ticketsPerPage, url]); + }, [ticketApiPage, ticketsPerPage, url]); return fetchState; } \ No newline at end of file