Created
May 30, 2025 11:47
-
-
Save sunmeat/56c2fc5e903affd1c675027cfea8993e to your computer and use it in GitHub Desktop.
отправка данных формы методом POST XMLHttpRequest REACT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {useState} from 'react'; | |
const PetForm = () => { | |
const [formData, setFormData] = useState({ | |
name: '', | |
status: 'available', | |
category: '', | |
tags: '', | |
photos: [], | |
}); | |
const [result, setResult] = useState(null); | |
const [error, setError] = useState(null); | |
const [modalVisible, setModalVisible] = useState(false); | |
const handleChange = (e) => { | |
const {name, value, files} = e.target; | |
if (name === 'photos') { | |
setFormData((prev) => ({...prev, photos: Array.from(files)})); | |
} else { | |
setFormData((prev) => ({...prev, [name]: value})); | |
} | |
}; | |
const validate = () => { | |
if (!formData.name.trim()) return 'Имя питомца обязательно.'; | |
if (!formData.status) return 'Статус обязателен.'; | |
return null; | |
}; | |
const handleSubmit = (e) => { | |
e.preventDefault(); | |
setError(null); | |
setResult(null); | |
const validationError = validate(); | |
if (validationError) { | |
setError(validationError); | |
return; | |
} | |
const xhr = new XMLHttpRequest(); | |
xhr.open('POST', 'https://petstore.swagger.io/v2/pet', true); | |
xhr.setRequestHeader('Content-Type', 'application/json'); | |
const tags = formData.tags | |
.split(',') | |
.map((tag) => tag.trim()) | |
.filter(Boolean) | |
.map((tag) => ({name: tag})); | |
const photoUrls = formData.photos.map((file) => URL.createObjectURL(file)); | |
const payload = { | |
name: formData.name, | |
status: formData.status, | |
category: formData.category ? {name: formData.category} : {}, | |
photoUrls, | |
tags, | |
}; | |
xhr.onreadystatechange = () => { | |
if (xhr.readyState === 4) { | |
photoUrls.forEach((url) => URL.revokeObjectURL(url)); | |
if (xhr.status === 200) { | |
const response = JSON.parse(xhr.responseText); | |
setResult(JSON.stringify(response, null, 2)); | |
setModalVisible(true); | |
} else { | |
setError(`Ошибка: ${xhr.status} ${xhr.statusText}`); | |
} | |
} | |
}; | |
xhr.onerror = () => { | |
setError('Ошибка сети.'); | |
}; | |
xhr.send(JSON.stringify(payload)); | |
}; | |
return ( | |
<> | |
<style>{` | |
body { | |
background-color: #121212; | |
font-family: Arial, sans-serif; | |
color: #fff; | |
} | |
.container { | |
max-width: 600px; | |
margin: 2rem auto; | |
background-color: #1e1e1e; | |
padding: 20px; | |
border-radius: 10px; | |
text-align: center; | |
} | |
form { | |
display: flex; | |
flex-direction: column; | |
gap: 15px; | |
text-align: left; | |
} | |
input, select, textarea { | |
padding: 8px; | |
border-radius: 5px; | |
border: none; | |
background-color: #2a2a2a; | |
color: #ffffff; | |
width: 100%; | |
box-sizing: border-box; | |
} | |
input[type='file'] { | |
padding: 8px 0; | |
} | |
textarea { | |
resize: vertical; | |
min-height: 80px; | |
} | |
button { | |
padding: 0.5rem 1rem; | |
margin-top: 10px; | |
border-radius: 5px; | |
border: none; | |
background-color: #1db954; | |
color: #ffffff; | |
cursor: pointer; | |
} | |
button:hover { | |
background-color: #1ed760; | |
} | |
.error { | |
color: #ff5555; | |
} | |
.modal-overlay { | |
position: fixed; | |
top: 0; left: 0; right: 0; bottom: 0; | |
background-color: rgba(0,0,0,0.7); | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
.modal { | |
background-color: #2a2a2a; | |
padding: 20px; | |
border-radius: 10px; | |
max-width: 500px; | |
width: 100%; | |
text-align: left; | |
} | |
.modal pre { | |
background-color: #1e1e1e; | |
padding: 10px; | |
border-radius: 5px; | |
white-space: pre-wrap; | |
word-wrap: break-word; | |
} | |
.modal button { | |
background-color: #555; | |
} | |
`}</style> | |
<div className="container"> | |
<h2>Добавить питомца в магазин</h2> | |
<form onSubmit={handleSubmit}> | |
<label htmlFor="name">Имя питомца:</label> | |
<input | |
type="text" | |
name="name" | |
id="name" | |
placeholder="Например, Барсик" | |
value={formData.name} | |
onChange={handleChange} | |
required | |
/> | |
<label htmlFor="status">Статус:</label> | |
<select | |
name="status" | |
id="status" | |
value={formData.status} | |
onChange={handleChange} | |
> | |
<option value="available">Доступен</option> | |
<option value="pending">В ожидании</option> | |
<option value="sold">Продан</option> | |
</select> | |
<label htmlFor="category">Категория:</label> | |
<input | |
type="text" | |
name="category" | |
id="category" | |
placeholder="Например, Dog" | |
value={formData.category} | |
onChange={handleChange} | |
/> | |
<label htmlFor="photos">Фотографии питомца:</label> | |
<input | |
type="file" | |
name="photos" | |
id="photos" | |
multiple | |
accept="image/*" | |
onChange={handleChange} | |
/> | |
<label htmlFor="tags">Теги (через запятую):</label> | |
<textarea | |
name="tags" | |
id="tags" | |
placeholder="Например, дружелюбный, игривый" | |
value={formData.tags} | |
onChange={handleChange} | |
/> | |
<button type="submit">Добавить питомца</button> | |
{error && <p className="error">{error}</p>} | |
</form> | |
</div> | |
{modalVisible && ( | |
<div className="modal-overlay" onClick={() => setModalVisible(false)}> | |
<div className="modal" onClick={(e) => e.stopPropagation()}> | |
<h3>Питомец успешно добавлен!</h3> | |
<pre>{result}</pre> | |
<button onClick={() => setModalVisible(false)}>Закрыть</button> | |
</div> | |
</div> | |
)} | |
</> | |
); | |
}; | |
export default PetForm; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment