У меня есть два файла:
- App.js
- useFetch.js
useFetch.js - это пользовательский хук, который я хочу использовать для выполнения запросов к определенному API с использованием fetch.
Это содержимое файла App.js:
import React, { useState } from 'react';
import useFetch from './hooks/useFetch';
...
const App = () => {
const [page, setPage] = useState(1);
const [data, error, setUrl, isLoading, abort] = useFetch();
const handleAction = () => {
if (isLoading) {
abort();
console.log('abort signal sended');
} else {
setUrl(`https://reqres.in/api/users?page=${page}`);
}
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<div
className="App-header-button"
>
<Button
variant="contained"
color={isLoading ? 'secondary' : 'primary'}
onClick={() => handleAction()}
>
{isLoading ? 'Cancel' : 'Test'}
</Button>
</div>
{data && 'Data loaded'}
<input type="text" onChange={event => setPage(event.target.value)} value={page} />
</header>
</div>
);
};
export default App;
Как видите, это простое приложение. Ввод в конце используется для настройки отображения страницы из API.
Это содержимое моего пользовательского useFetch.js:
import { useState, useEffect } from 'react';
const useFetch = (defaultUrl) => {
const [url, setUrl] = useState(defaultUrl);
const [data, setData] = useState();
const [error, setError] = useState();
const [isLoading, setIsLoading] = useState(false);
const [controller] = useState(new AbortController());
const { signal } = controller;
useEffect(() => {
if (url) {
setIsLoading(true);
fetch(url, { signal })
.then(res => res.json())
.then((res) => {
setData(res.data);
setIsLoading(false);
})
.catch((err) => {
setError(err);
console.log(err.name);
setIsLoading(false);
});
}
}, [url]);
const abort = () => {
controller.abort();
setIsLoading(false);
};
return [
data,
error,
setUrl,
isLoading,
abort,
];
};
export default useFetch;
У меня есть одна проблема ... она работает очень хорошо и отображает данные, когда я меняю страницу и нажимаю кнопку. Проблема заключается в следующем: если я нажимаю кнопку со страницей и снова нажимаю кнопку с той же страницей, ничего не происходит. Это имеет определенный смысл, потому что URL-адрес не меняется, все равно будут те же данные, отправленные на крючок. Предположим, пользователь хочет обновить данные той же страницей, снова нажав кнопку. В этом случае мне нужно, чтобы ловушка снова сделала тот же вызов, повторяя тот же URL. Итак, как я могу сделать так, чтобы крюк снова «рендерил» его?
[ОБНОВЛЕНИЕ I]
С помощью @Atul я внес эти изменения и работает. Мне только интересно, является ли это хорошим способом или наиболее подходящим способом достижения этого.
На useFetch.js:
useEffect(() => {
if (url && refreshFlag) {
setIsLoading(true);
fetch(url, { signal })
.then(res => res.json())
.then((res) => {
setData(res.data);
setIsLoading(false);
setRefreshFlag(false);
})
.catch((err) => {
setError(err);
console.log(err.name);
setRefreshFlag(false);
setIsLoading(false);
});
}
}, [url, refreshFlag]);
В App.js: (отображается только код действия кнопки)
const handleAction = () => {
if (isLoading) {
abort();
console.log('abort signal sended');
} else {
refresh(true);
setUrl(`https://reqres.in/api/users?page=${page}`);
}
};