У меня есть общий метод использования useQuery или useMutation на основе метода HTTP в качестве опоры. Но тип возвращаемого значения этого метода содержит «QueryObserverRefetchErrorResult<any, Error>», который не имеет методов, включенных в useMutation или useQuery.
Я пробовал условные типы, такие как, но проблема была той же.
type ResultType<Method extends NTWRK_METHODS> = Method extends NTWRK_METHODS.GET ? NetworkQueryResult : NetworkMutationResult;
Мой метод
type NetworkQueryResult = UseQueryResult<any, Error>;
type NetworkMutationResult = UseMutationResult<any, Error, void, unknown>;
export function useNetworkQuery(
props: IUseNetworkCallWithClient,
): NetworkQueryResult | NetworkMutationResult {
const {queryKey, axiosClient, url, persist, method, params = ''} = props;
if (method === NTWRK_METHODS.GET) {
return useQuery({
queryKey: [queryKey],
queryFn: async () => {
const data = await axiosClient.request({
method: NTWRK_METHODS.GET,
url: url,
params: params,
});
return data.data;
},
enabled: false,
meta: {persist},
});
} else {
return useMutation({
mutationKey: [queryKey],
mutationFn: async () => {
const data = await axiosClient.request({
method: method,
url: url,
data: params,
});
return data.data;
},
meta: {persist},
});
}
}
Я называю это так
export const makeNetworkCall = (props: IUseNetworkCallWithoutClient) => {
const {method, queryKey, url, persist, params = ''} = props;
const config = {
axiosClient,
queryKey: queryKey,
method: method,
url: url,
persist: persist,
params: params,
};
return useNetworkQuery(config);
};
а потом
export const useAuthCalls = () => {
const logIn = () => {
makeNetworkCall({
method: NTWRK_METHODS.POST,
url: '/users',
queryKey: 'login',
persist: true,
params: '',
});
};
return {logIn};
};
да, это перечисление, и повторяющийся код был ошибкой, отредактирован и исправлен.
Небольшое примечание: как я вижу, как вы определяете эти функции, особенно makeNetworkCall (у которого нет префикса use, но все же является ловушкой), у вас может возникнуть соблазн вызвать их в обработчиках действий (например, onClick кнопки) . Имейте в виду, что они по-прежнему являются хуками и должны всегда вызываться в одном и том же порядке при рендеринге в компоненте React. Если вы попытаетесь вызвать свой метод logIn, например, при нажатии кнопки, вы, вероятно, получите предупреждение, если не настоящую ошибку.
Вы правы, и спасибо, что поправили меня, я действительно получил предупреждение. В том же порядке вы имеете в виду, что я должен вызвать метод входа в систему, затем makeNetworkCall, а затем usenetworkquery?
Нет, тот же порядок подразумевает, что хуки следует вызывать всегда при рендеринге компонента. Например, вы не должны условно вызывать хуки. Вызов перехватчика из обработчика действий по определению условен, поскольку он будет вызываться только при нажатии кнопки. Ваша текущая реализация имеет ошибочный дизайн, потому что, чтобы избежать этого предупреждения, вам придется вызывать login каждый раз, когда ваш компонент повторно визуализируется.
Более того, useMutation фактически не запускает запрос при вызове, он возвращает функции mutate и mutateAsync, которые можно использовать для фактического запуска запроса. Это те, которые вы должны использовать в своих обработчиках действий, а не сами useMutation.
Понятно, мне следует запустить перехватчик при рендеринге и, возможно, использовать mutate как многоразовый метод. Совсем забыл правило не вызывать хук условно.





Несмотря на то, что мы обсуждали ранее в комментариях, я дам вам ответ относительно ввода вашей функции useNetworkQuery, и это примерно то, о чем вы спрашиваете в этом посте.
Что вам здесь нужно, так это перегрузка функции, чтобы помочь различить, что возвращает useNetworkQuery.
Простое определение типа возвращаемого значения вашей функции как NetworkQueryResult | NetworkMutationResult не будет работать достаточно хорошо, потому что TypeScript не сможет определить, какой из этих двух является возвращаемым, а только то, что все возвращаемое может быть одним из этих «поэтому относитесь к ним так, как будто они были оба».
Как насчет замены useNetworkQuery на это?
export function useNetworkQuery<TData = any, TError extends Error = Error>(props: Exclude<IUseNetworkCallWithClient, "method"> & { method: NTWRK_METHODS.GET; }): UseQueryResult<TData, TError>;
export function useNetworkQuery<TData = any, TError extends Error = Error, TVariables = any>(props: Exclude<IUseNetworkCallWithClient, "method"> & { method: Exclude<NTWRK_METHODS, NTWRK_METHODS.GET>; }): UseMutationResult<TData, TError, TVariables>;
export function useNetworkQuery<TData = any, TError extends Error = Error, TVariables = any>(props: IUseNetworkCallWithClient): UseQueryResult<TData, TError> | UseMutationResult<TData, TError, TVariables> {
const { queryKey, axiosClient, url, persist, method, params = "" } = props;
if (method === NTWRK_METHODS.GET) {
return useQuery<TData, TError>({
queryKey: [queryKey],
queryFn: async () => {
const data = await axiosClient.request({
method: NTWRK_METHODS.GET,
url: url,
params: params,
});
return data.data;
},
enabled: false,
meta: { persist },
});
}
return useMutation<TData, TError, TVariables>({
mutationKey: [queryKey],
mutationFn: async () => {
const data = await axiosClient.request({
method: method,
url: url,
data: params,
});
return data.data;
},
meta: { persist },
});
}
Небольшое пояснение по этому поводу:
UseQueryResult<TData, TError>, если данное props включает свойство method, равное NTWRK_METHODS.GET, или меняет его на UseMutationResult<TData, TError, TVariables> для любого другого NTWRK_METHODS, которое не является NTWRK_METHODS.GET.TData, TError и TVariables, которые являются дженериками, принимаемыми функциями useQuery и useMutation. Таким образом, ваша функция useNetworkQuery сможет сохранять правильное поведение при наборе текста вместо того, чтобы все устанавливать на any.Предыдущая функция должна работать достаточно хорошо, а как насчет makeNetworkCall? Если вы попытаетесь вернуть useNetworkQuery напрямую, вы заметите, что получите сообщение об ошибке, сообщающее, что сигнатура вызова реализации не видна извне. Это связано с тем, что когда вы перегружаете функцию, при вызове функции учитываются только сигнатуры перегрузки, а сигнатуры реализации служат только для реализации.
Затем вам следует добавить дополнительную перегрузку к useNetworkQuery:
export function useNetworkQuery<TData = any, TError extends Error = Error, TVariables = any>(props: IUseNetworkCallWithClient): UseQueryResult<TData, TError> | UseMutationResult<TData, TError, TVariables>;
По сути, это та же подпись, что и реализация.
Теперь вы можете перегрузить свою функцию makeNetworkCall:
export function makeNetworkCall<TData = any, TError extends Error = Error>(props: Exclude<IUseNetworkCallWithClient, "method"> & { method: NTWRK_METHODS.GET; }): UseQueryResult<TData, TError>;
export function makeNetworkCall<TData = any, TError extends Error = Error, TVariables = any>(props: Exclude<IUseNetworkCallWithClient, "method"> & { method: Exclude<NTWRK_METHODS, NTWRK_METHODS.GET>; }): UseMutationResult<TData, TError, TVariables>;
export function makeNetworkCall<TData = any,TError extends Error = Error,TVariables = any>(props: IUseNetworkCallWithClient): UseQueryResult<TData, TError> | UseMutationResult<TData, TError, TVariables>;
export function makeNetworkCall(props: IUseNetworkCallWithoutClient) {
const { method, queryKey, url, persist, params = "" } = props;
const config = {
axiosClient,
queryKey: queryKey,
method: method,
url: url,
persist: persist,
params: params,
};
return useNetworkQuery(config);
}
Наконец, вы можете вызвать хук makeNetworkCall из своих компонентов:
const getQuery = makeNetworkCall({ method: NTWRK_METHODS.GET }); // Type is UseQueryResult.
const postQuery = makeNetworkCall({ method: NTWRK_METHODS.POST }); // Type is UseMutationResult.
В качестве примечания относительно крючка useAuthCalls...
А как насчет замены на:
export const useAuthCalls = () => {
const logInMutation = makeNetworkCall({
method: NTWRK_METHODS.POST,
url: "/users",
queryKey: "login",
persist: true,
params: "",
});
return {
logIn: logInMutation.mutateAsync,
};
};
Таким образом, вы всегда используете перехватчик makeNetworkCall и возвращаете mutateAsync только для вызова logIn. Вы сможете без проблем вызывать это из своих обработчиков действий.
В качестве предложения переименуйте свой makeNetworkCall во что-то, что начинается с use. Причина этого в том, чтобы напомнить вам, что на самом деле это крючок и к нему следует относиться как к таковому. Это означает, что его всегда следует вызывать по порядку и только внутри компонентов React.
Если это поможет вам лучше это представить, вот CodeSandbox, который вы можете проверить:
Это сработало отлично, но позже я понял, что использовать перехватчики в условных операторах — не лучшая практика, поэтому теперь я использую два разных метода. Хотя решение, которое вы дали, было правильным
Быстрые вопросы. Является ли
NTWRK_METHODSперечислением ? Последние два фрагмента кода абсолютно одинаковы, было ли это ошибкой? Являются лиmakeNetworkCallиuseNetworkQueryодинаковыми функциями или разными?