Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Created May 30, 2025 12:32
Show Gist options
  • Save sunmeat/f8bbe4cdd223f9c66478d1d90d6a7ed0 to your computer and use it in GitHub Desktop.
Save sunmeat/f8bbe4cdd223f9c66478d1d90d6a7ed0 to your computer and use it in GitHub Desktop.
привязка запроса к ЖЦ компоненты
import React, {useState, useEffect, useRef} from 'react';
const styles = {
container: {
fontFamily: 'Arial, sans-serif',
backgroundColor: '#121212',
color: '#fff',
textAlign: 'center',
padding: '2rem',
minHeight: '100vh',
},
box: {
maxWidth: 800,
margin: '0 auto',
backgroundColor: '#1e1e1e',
padding: 20,
borderRadius: 10,
textAlign: 'left',
},
button: {
padding: '0.5rem 1rem',
margin: '0.5rem',
borderRadius: 5,
border: 'none',
backgroundColor: '#1db954',
color: '#fff',
cursor: 'pointer',
},
buttonHover: {
backgroundColor: '#1ed760',
},
pre: {
backgroundColor: '#2a2a2a',
padding: 10,
borderRadius: 5,
whiteSpace: 'pre-wrap',
wordWrap: 'break-word',
},
img: {
maxWidth: '100%',
borderRadius: 10,
margin: '1rem 0',
},
error: {
color: '#ff5555',
},
};
const textUrl =
'https://gist.githubusercontent.com/sunmeat/5120f241ab0f407138b7c1dc479a2f02/raw/a01e873da40a27bada0192e4e75e632586623329/index.html';
const imageUrl =
'https://raw.githubusercontent.com/sunmeat/gallery/main/MyApplication/cats/cat%20(1).jpg';
const jsonObjectUrl = 'https://jsonplaceholder.typicode.com/users/1';
const jsonArrayUrl = 'https://jsonplaceholder.typicode.com/posts';
const postUrl = 'https://petstore.swagger.io/v2/pet';
const FetchExample = () => {
// применяем рефы для контроллеров отмены запросов - привязка к ЖЦ компонента
const textController = useRef(null);
const imageController = useRef(null);
const jsonObjectController = useRef(null);
const jsonArrayController = useRef(null);
const postController = useRef(null);
// реф для хранения URL объектов изображений, для их очистки
const imageUrlRef = useRef(null);
const [textContent, setTextContent] = useState('');
const [textLoading, setTextLoading] = useState(false);
const [textError, setTextError] = useState('');
const [imageBlob, setImageBlob] = useState(null);
const [imageLoading, setImageLoading] = useState(false);
const [imageError, setImageError] = useState('');
const [jsonObject, setJsonObject] = useState('');
const [jsonObjectLoading, setJsonObjectLoading] = useState(false);
const [jsonObjectError, setJsonObjectError] = useState('');
const [jsonArray, setJsonArray] = useState('');
const [jsonArrayLoading, setJsonArrayLoading] = useState(false);
const [jsonArrayError, setJsonArrayError] = useState('');
const [postResult, setPostResult] = useState('');
const [postLoading, setPostLoading] = useState(false);
const [postError, setPostError] = useState('');
// очистка ресурсов при размонтировании компонента
useEffect(() => {
return () => {
// отменяем все активные запросы!
textController.current?.abort();
imageController.current?.abort();
jsonObjectController.current?.abort();
jsonArrayController.current?.abort();
postController.current?.abort();
// освобождаем объекты изображений
if (imageUrlRef.current) {
URL.revokeObjectURL(imageUrlRef.current);
}
};
}, []);
// очистка предыдущего URL объекта при загрузке нового изображения
useEffect(() => {
return () => {
if (imageUrlRef.current) {
URL.revokeObjectURL(imageUrlRef.current);
}
};
}, [imageBlob]);
async function loadText() {
// отменяем предыдущий запрос если он есть
textController.current?.abort();
// создаём новый контроллер для отмены запроса
textController.current = new AbortController();
setTextLoading(true);
setTextError('');
setTextContent('');
try {
const response = await fetch(textUrl, {
signal: textController.current.signal // привязываем к контроллеру
});
if (!response.ok)
throw new Error(`Ошибка: ${response.status} ${response.statusText}`);
const content = await response.text();
setTextContent(content);
} catch (error) {
// игнорируем ошибки отмены запроса
if (error.name !== 'AbortError') {
setTextError(error.message);
}
} finally {
setTextLoading(false);
}
}
function downloadText() {
if (!textContent) return;
const blob = new Blob([textContent], {type: 'text/plain'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'file.txt';
a.click();
URL.revokeObjectURL(url);
}
async function loadImage() {
// отменяем предыдущий запрос если он есть
imageController.current?.abort();
// создаём новый контроллер для отмены запроса
imageController.current = new AbortController();
setImageLoading(true);
setImageError('');
setImageBlob(null);
// очищаем предыдущий URL объект
if (imageUrlRef.current) {
URL.revokeObjectURL(imageUrlRef.current);
imageUrlRef.current = null;
}
try {
const response = await fetch(imageUrl, {
signal: imageController.current.signal // привязываем к контроллеру
});
if (!response.ok)
throw new Error(`Ошибка: ${response.status} ${response.statusText}`);
const blob = await response.blob();
setImageBlob(blob);
} catch (error) {
// игнорируем ошибки отмены запроса
if (error.name !== 'AbortError') {
setImageError(error.message);
}
} finally {
setImageLoading(false);
}
}
function downloadImage() {
if (!imageBlob) return;
const url = URL.createObjectURL(imageBlob);
const a = document.createElement('a');
a.href = url;
a.download = 'image.jpg';
a.click();
URL.revokeObjectURL(url);
}
async function loadJsonObject() {
// отменяем предыдущий запрос если он есть
jsonObjectController.current?.abort();
// создаём новый контроллер для отмены запроса
jsonObjectController.current = new AbortController();
setJsonObjectLoading(true);
setJsonObjectError('');
setJsonObject('');
try {
const response = await fetch(jsonObjectUrl, {
signal: jsonObjectController.current.signal // привязываем к контроллеру
});
if (!response.ok)
throw new Error(`Ошибка: ${response.status} ${response.statusText}`);
const json = await response.json();
setJsonObject(JSON.stringify(json, null, 2));
} catch (error) {
// игнорируем ошибки отмены запроса
if (error.name !== 'AbortError') {
setJsonObjectError(error.message);
}
} finally {
setJsonObjectLoading(false);
}
}
function downloadJsonObject() {
if (!jsonObject) return;
const blob = new Blob([jsonObject], {type: 'application/json'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'user.json';
a.click();
URL.revokeObjectURL(url);
}
async function loadJsonArray() {
// отменяем предыдущий запрос если он есть
jsonArrayController.current?.abort();
// создаём новый контроллер для отмены запроса
jsonArrayController.current = new AbortController();
setJsonArrayLoading(true);
setJsonArrayError('');
setJsonArray('');
try {
const response = await fetch(jsonArrayUrl, {
signal: jsonArrayController.current.signal // привязываем к контроллеру
});
if (!response.ok)
throw new Error(`Ошибка: ${response.status} ${response.statusText}`);
const json = await response.json();
setJsonArray(JSON.stringify(json, null, 2));
} catch (error) {
// игнорируем ошибки отмены запроса
if (error.name !== 'AbortError') {
setJsonArrayError(error.message);
}
} finally {
setJsonArrayLoading(false);
}
}
function downloadJsonArray() {
if (!jsonArray) return;
const blob = new Blob([jsonArray], {type: 'application/json'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'posts.json';
a.click();
URL.revokeObjectURL(url);
}
async function sendPost() {
// отменяем предыдущий запрос если он есть
postController.current?.abort();
// создаём новый контроллер для отмены запроса
postController.current = new AbortController();
setPostLoading(true);
setPostError('');
setPostResult('');
try {
const response = await fetch(postUrl, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({name: 'Fluffy', status: 'available'}),
signal: postController.current.signal // привязываем к контроллеру
});
if (!response.ok)
throw new Error(`Ошибка: ${response.status} ${response.statusText}`);
const json = await response.json();
setPostResult(JSON.stringify(json, null, 2));
} catch (error) {
// игнорируем ошибки отмены запроса
if (error.name !== 'AbortError') {
setPostError(error.message);
}
} finally {
setPostLoading(false);
}
}
return (
<div style={styles.container}>
<div style={styles.box}>
<h2>Текстовый файл</h2>
<button style={styles.button} onClick={loadText} disabled={textLoading}>
{textLoading ? 'Загрузка...' : 'Загрузить текст'}
</button>
{textContent && (
<>
<p>Текстовый файл загружен:</p>
<pre style={styles.pre}>{textContent}</pre>
<button style={styles.button} onClick={downloadText}>
Скачать файл
</button>
</>
)}
{textError && <p style={styles.error}>{textError}</p>}
</div>
<div style={styles.box}>
<h2>Изображение</h2>
<button style={styles.button} onClick={loadImage} disabled={imageLoading}>
{imageLoading ? 'Загрузка...' : 'Загрузить изображение'}
</button>
{imageBlob && (
<>
<p>Изображение загружено:</p>
<img
style={styles.img}
src={(() => {
// создаём и сохраняем URL объект для последующей очистки
if (imageUrlRef.current) {
URL.revokeObjectURL(imageUrlRef.current);
}
imageUrlRef.current = URL.createObjectURL(imageBlob);
return imageUrlRef.current;
})()}
alt="Загруженное"
/>
<button style={styles.button} onClick={downloadImage}>
Скачать изображение
</button>
</>
)}
{imageError && <p style={styles.error}>{imageError}</p>}
</div>
<div style={styles.box}>
<h2>JSON-объект</h2>
<button
style={styles.button}
onClick={loadJsonObject}
disabled={jsonObjectLoading}
>
{jsonObjectLoading ? 'Загрузка...' : 'Загрузить JSON-объект'}
</button>
{jsonObject && (
<>
<p>JSON-объект загружен:</p>
<pre style={styles.pre}>{jsonObject}</pre>
<button style={styles.button} onClick={downloadJsonObject}>
Скачать JSON
</button>
</>
)}
{jsonObjectError && <p style={styles.error}>{jsonObjectError}</p>}
</div>
<div style={styles.box}>
<h2>JSON-массив</h2>
<button
style={styles.button}
onClick={loadJsonArray}
disabled={jsonArrayLoading}
>
{jsonArrayLoading ? 'Загрузка...' : 'Загрузить JSON-массив'}
</button>
{jsonArray && (
<>
<p>JSON-массив загружен:</p>
<pre style={styles.pre}>{jsonArray}</pre>
<button style={styles.button} onClick={downloadJsonArray}>
Скачать JSON
</button>
</>
)}
{jsonArrayError && <p style={styles.error}>{jsonArrayError}</p>}
</div>
<div style={styles.box}>
<h2>POST-запрос</h2>
<button style={styles.button} onClick={sendPost} disabled={postLoading}>
{postLoading ? 'Отправка...' : 'Отправить POST'}
</button>
{postResult && (
<>
<p>Питомец успешно добавлен в магазин:</p>
<pre style={styles.pre}>{postResult}</pre>
</>
)}
{postError && <p style={styles.error}>{postError}</p>}
</div>
</div>
);
};
export default FetchExample;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment