Nexjs обновления адресной строки блокирует любые запросы

Есть проблемка что при использование nextjs изменение адресной строки одновременно с запросом tanstack-query, он не выполняется, почему?

Приведу 2 примера: На странице предположим есть 2 компонента AddCategoryModal.tsx и ClassesTable.tsx В AddCategoryModal при открытие мы добавляем в адресную строку что модальное окно открыто, а в ClassesTable это таблица которая делает запрос к дб, получает данные и рисует таблицу.

AddCategoryModal.tsx

useEffect(() => {
    if (isOpen) {
        const params = new URLSearchParams(searchParams);
        params.set('addCategory', 'true');
        replace(`${pathname}?${params}`, {
            scroll: false,
        });
    }
    else {
        const params = new URLSearchParams(searchParams);
        params.delete('addCategory');
        replace(`${pathname}?${params}`, {
            scroll: false,
        });
    }
}, [isOpen])

Я понимаю что такой useEffect не правильно писать, не очень красиво не в этом суть, это для теста, тут при загрузки страницы, так-как стоит strict mode у нас отрабатывает useEffect со значением isOpen=false тем самым мы выполняем else где просто удаляем того чего и так нету :) Одновременно с этим выполняем компонент.

ClassesTable.tsx

const allClassesData = queryGetAllClasses();

const {
    classes, isError, isLoading, ...rest
} = {
    classes: allClassesData?.data?.classesData?.classes,
    isError: allClassesData?.isError,
    isLoading: allClassesData?.isLoading || allClassesData?.isRefetching,
    rest: { ...allClassesData }
};

Тут я использую tanstack-query

export const queryGetAllClasses = () => {
    console.log('queryGetAllClasses');
    return useQuery({
        queryKey: ['getClasses'],
        queryFn: async () => await apiGetClasses(),
        refetchOnWindowFocus: false,
        placeholderData: keepPreviousData,
    });
}

Все легко и логично функция на apiGetClasses которая выполняется уже на сервере next.

export const apiGetClasses = async (
    // TODO: Реализовать пагинацию и лимиты
): Promise<ApiResponse & {
    classesData?: {
        classes: ClassesDto[],
        totalCount: number,
    }
}> => {
    await waiting();
    console.log('apiGetClasses');
    try {
        ...
    }
    catch (e) {
        console.log('renameImage err:', e);
        return { isSuccess: false, status: 'error', message: e.sqlMessage ?? (e.message ?? e) };
    }
}

Теперь объясняю что происходит, при загрузке страницы, мы меняем адресную строку из-за useEffect в этот момент отрабатывает queryGetAllClasses внутри консоль console.log('queryGetAllClasses'); отрабатывает, значит мы попадаем туда и все окей, но вот уже apiGetClasses не отрабатывает, и не возвращает данные, запрос просто теряется в небытие.

Другой пример: При открытие модального окна, ставим setIsOpen((isOpen) => !isOpen) меняем его на true в этот момент так-же меняем адресную строку вставляя что модальное окно открыто, вместе с этим делаем запрос на сервер 2 запроса один например(как было у меня) на получения класса по id и второй на получения всех учителей из базы данных. Таким образом query отрабатывает оба раза, но api отрабатывает только первый, так-как на время 2, у нас происходит замена адресной строки, тем самым 2 запрос просто теряется в небытие.

код

const UserEditModal = ({
    user,
    icon,
    label,
}: {
    user: UserDto,
    icon?: React.ReactNode,
    label?: string
}) => {
    const searchParams = useSearchParams();
    const { replace } = useRouter();
    const pathname = usePathname();

    const isEdit = searchParams.get('edit');

    const [isOpen, setIsOpen] = useState<boolean>(isEdit && isEdit.toString() === user.id.toString() ? true : false);
    const [isDisabled, setIsDisabled] = useState<boolean>(false);
    const buttonRef = useRef(null);

    const onOpenModal = () => {
        const params = new URLSearchParams(searchParams);
        params.set('edit', `${user.id}`);
        replace(`${pathname}?${params}`, {
            scroll: false,
        });
    }

    const onCloseModal = () => {
        const params = new URLSearchParams(searchParams);
        params.delete('edit');
        replace(`${pathname}?${params}`, {
            scroll: false,
        });
    }

    useEffect(() => {
        if (buttonRef?.current && isOpen) {
            buttonRef.current.focus();
        }
    }, [isOpen])

    return (
        <>
            <Button
                size='verySmall'
                theme='transparent'
                onClick={() => setIsOpen((prev) => !prev)}
                disabled={isOpen}
            >
                {icon ? icon : <MdOutlineModeEditOutline size={18} />}
                {label && <>
                    {' '}
                    {label}
                </>}
            </Button>

            <ModalEditUser
                isOpen={isOpen}
                setIsOpen={setIsOpen}
                className={{
                    base: 'w-full max-w-[420px] min-h-[270px]'
                }}
                willOpen={onOpenModal}
                willClose={onCloseModal}
            >
                ...
            </ModalEditUser>
        </>
    );
};

export default UserEditModal;

При открытые срабатывает onOpenModal() который меняет адресную строку внутри формы EditUserForm

const EditUserForm = ({
    ...
}: {
    ...
}) => {
    const test1 = queryGetClassById(1);
    const test2 = queryGetAllTeachers();
    ...

    return (
        <form>
          ...
        </form>
    );
};

export default EditUserForm;

И в данном примере получим что queryGetClassById отработает так-как срабатывает перед заменой строки, queryGetAllTeachers уже не успевает, для имитации на запросе стоит задержка 2 секунды, проблема в том-что при смене адресной строки запрос теряется, и не выполняется, и я не понимаю в чем проблема, может есть идеи?

  • Заметил что в nextjs файл 'use server' обрабатывает по одному запросу, тем самым если не менять адресную строку, то начинает отрабатывать первый, а второй ждет, после завершения первого, начинает работать второй, а при изменение адресной строки, если она совпадает с запросам, то он отменяется.

Ответы (0 шт):