Вот код useFetch
, который я построил, и который в значительной степени основан на нескольких известных статьях на эту тему:
const dataFetchReducer = (state: any, action: any) => {
let data, status, url;
if (action.payload && action.payload.config) {
({ data, status } = action.payload);
({ url } = action.payload.config);
}
switch (action.type) {
case 'FETCH_INIT':
return {
...state,
isLoading: true,
isError: false
};
case 'FETCH_SUCCESS':
return {
...state,
isLoading: false,
isError: false,
data: data,
status: status,
url: url
};
case 'FETCH_FAILURE':
return {
...state,
isLoading: false,
isError: true,
data: null,
status: status,
url: url
};
default:
throw new Error();
}
}
/**
* GET data from endpoints using AWS Access Token
* @param {string} initialUrl The full path of the endpoint to query
* @param {JSON} initialData Used to initially populate 'data'
*/
export const useFetch = (initialUrl: ?string, initialData: any) => {
const [url, setUrl] = useState<?string>(initialUrl);
const { appStore } = useContext(AppContext);
console.log('useFetch: url = ', url);
const [state, dispatch] = useReducer(dataFetchReducer, {
isLoading: false,
isError: false,
data: initialData,
status: null,
url: url
});
useEffect(() => {
console.log('Starting useEffect in requests.useFetch', Date.now());
let didCancel = false;
const options = appStore.awsConfig;
const fetchData = async () => {
dispatch({ type: 'FETCH_INIT' });
try {
let response = {};
if (url && options) {
response = await axios.get(url, options);
}
if (!didCancel) {
dispatch({ type: 'FETCH_SUCCESS', payload: response });
}
} catch (error) {
// We won't force an error if there's no URL
if (!didCancel && url !== null) {
dispatch({ type: 'FETCH_FAILURE', payload: error.response });
}
}
};
fetchData();
return () => {
didCancel = true;
};
}, [url, appStore.awsConfig]);
return [state, setUrl];
}
Это работает нормально, за исключением одного варианта использования:
Представьте себе, что введено новое имя клиента, имя пользователя или адрес электронной почты - часть данных, которую необходимо проверить, чтобы убедиться, что она уже существует, чтобы убедиться, что такие вещи остаются уникальными.
Итак, в качестве примера, скажем, пользователь вводит «Моя существующая компания» в качестве названия компании, и эта компания уже существует.Они вводят данные и нажимают Submit
.Событие Click этой кнопки будет подключено так, что будет вызван асинхронный запрос к конечной точке API - что-то вроде этого: companyFetch('acct_mgmt/companies/name/My%20Existing%20Company')
Затем в компоненте будет создана конструкция useEffect
, котораябудет ожидать ответа от конечной точки.Такой код может выглядеть следующим образом:
useEffect(() => {
if (!companyName.isLoading && acctMgmtContext.companyName.length > 0) {
if (fleetName.status === 200) {
const errorMessage = 'This company name already exists in the system.';
updateValidationErrors(name, {type: 'fetch', message: errorMessage});
} else {
clearValidationError(name);
changeWizardIndex('+1');
}
}
}, [companyName.isLoading, companyName.isError, companyName.data]);
В этом коде чуть выше отображается ошибка, если существует название компании.Если он еще не существует, мастер, в котором находится этот компонент, будет двигаться вперед.Ключевым выводом здесь является то, что вся логика обработки ответа содержится в useEffect
.
. Все это работает нормально, если пользователь не вводит одно и то же название компании дважды подряд.В этом конкретном случае зависимость url
в экземпляре companyFetch
для useFetch
не изменяется, и, следовательно, новый запрос к конечной точке API не отправляется.
Я могу придумать несколько способов попробоватьчтобы решить это, но все они кажутся взломами.Я думаю, что другие, должно быть, сталкивались с этой проблемой прежде, и мне любопытно, как они решили ее.