synapse-storage
Version:
Набор инструментов для управления состоянием и апи-запросами
85 lines (80 loc) • 2.89 kB
JavaScript
import { useCallback, useEffect, useRef, useState } from "react";
const IDLE_STATE = {
status: 'idle',
data: undefined,
error: undefined
};
/**
* Хук для выполнения мутаций (POST/PUT/DELETE/PATCH) через эндпоинт ApiClient.
*
* В отличие от {@link useApiQuery}, запрос не стартует автоматически — его
* запускает `mutate`/`mutateAsync`. Мутации не кэшируются (по REST-методу), а их
* `invalidatesTags` инвалидируют кэш — активные `useApiQuery` соседних эндпоинтов
* автоматически перезапросятся через шину инвалидации.
*
* @example
* const { mutate, isLoading } = useApiMutation(endpoints.createUser)
* mutate({ name: 'Alex' })
*/ function useApiMutation(endpoint, options = {}) {
const optionsRef = useRef(options);
optionsRef.current = options;
const [state, setState] = useState(IDLE_STATE);
const reqRef = useRef(null);
const mountedRef = useRef(true);
useEffect(()=>{
mountedRef.current = true;
return ()=>{
mountedRef.current = false;
reqRef.current?.abort();
};
}, []);
const mutateAsync = useCallback(async (params)=>{
setState({
status: 'loading',
data: undefined,
error: undefined
});
const req = endpoint.request(params, optionsRef.current);
reqRef.current = req;
try {
const res = await req.wait();
// wait() реджектится на !ok, но подстрахуемся
if (!res.ok) throw res.error ?? new Error('Mutation failed');
if (mountedRef.current) setState({
status: 'success',
data: res.data,
error: undefined
});
return res;
} catch (err) {
if (mountedRef.current) setState({
status: 'error',
data: undefined,
error: err
});
throw err;
}
}, [
endpoint
]);
const mutate = useCallback((params)=>{
// Намеренно глотаем reject — состояние ошибки уже выставлено в mutateAsync
mutateAsync(params).catch(()=>{});
}, [
mutateAsync
]);
const reset = useCallback(()=>setState(IDLE_STATE), []);
return {
mutate,
mutateAsync,
data: state.data,
error: state.error,
status: state.status,
isLoading: state.status === 'loading',
isError: state.status === 'error',
isSuccess: state.status === 'success',
reset
};
}
export { useApiMutation };
//# sourceMappingURL=useApiMutation.js.map