Created
May 30, 2025 12:05
-
-
Save sunmeat/0bd5d4a5fcf82b0344564029d521cd59 to your computer and use it in GitHub Desktop.
Jokes API + fetch 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'; | |
// CSS-in-JS стили | |
const styles = { | |
body: { | |
fontFamily: "'Courier New', monospace", | |
backgroundColor: '#121212', | |
color: '#ffffff', | |
padding: '2rem', | |
margin: 0, | |
minHeight: '100vh', | |
}, | |
container: { | |
maxWidth: '800px', | |
margin: '0 auto', | |
backgroundColor: '#1e1e1e', | |
padding: '20px', | |
borderRadius: '10px', | |
}, | |
button: { | |
padding: '0.5rem 1rem', | |
margin: '10px', | |
borderRadius: '5px', | |
border: 'none', | |
backgroundColor: '#1db954', | |
color: '#ffffff', | |
cursor: 'pointer', | |
fontSize: '16px', | |
}, | |
jokeBox: (frameColor, textColor) => ({ | |
margin: '20px 0', | |
padding: '10px', | |
border: `2px solid ${frameColor}`, | |
borderRadius: '5px', | |
width: 'fit-content', | |
maxWidth: '100%', | |
color: textColor, | |
boxSizing: 'border-box', | |
}), | |
jokeHeader: { | |
textAlign: 'center', | |
marginBottom: '10px', | |
fontWeight: 'bold', | |
}, | |
jokeContent: { | |
whiteSpace: 'pre-wrap', | |
wordWrap: 'break-word', | |
padding: '0 10px', | |
}, | |
error: { | |
color: '#ff5555', | |
margin: '10px 0', | |
}, | |
}; | |
const colorPairs = [ | |
{frame: '#8B0000', text: '#FF0000'}, | |
{frame: '#006400', text: '#00FF00'}, | |
{frame: '#00008B', text: '#0000FF'}, | |
{frame: '#BDB76B', text: '#FFFF00'}, | |
{frame: '#008B8B', text: '#00FFFF'}, | |
{frame: '#8B008B', text: '#FF00FF'}, | |
]; | |
const getFrameAndTextColors = () => { | |
const random = Math.floor(Math.random() * colorPairs.length); | |
return colorPairs[random]; | |
}; | |
const wrapText = (text, lineWidth) => { | |
const lines = []; | |
const splitByNewLine = text.split('\n'); | |
for (const part of splitByNewLine) { | |
let remaining = part; | |
while (remaining.length > lineWidth) { | |
let splitIndex = remaining.lastIndexOf(' ', lineWidth); | |
if (splitIndex <= 0) splitIndex = lineWidth; | |
lines.push(remaining.substring(0, splitIndex)); | |
remaining = remaining.substring(splitIndex).trimStart(); | |
} | |
lines.push(remaining); | |
} | |
return lines; | |
}; | |
const getJokeContent = (joke) => { | |
return joke.type === 'single' ? joke.joke : `${joke.setup}\n${joke.delivery}`; | |
}; | |
const JokeBox = ({joke, index}) => { | |
const {frame, text} = getFrameAndTextColors(); | |
const wrapped = wrapText(getJokeContent(joke), 48); // boxWidth - 4 | |
return ( | |
<div style={styles.jokeBox(frame, text)}> | |
<div style={styles.jokeHeader}>Шутка #{index}</div> | |
<div style={styles.jokeContent}>{wrapped.join('\n')}</div> | |
</div> | |
); | |
}; | |
const JokeApp = () => { | |
const [jokes, setJokes] = useState([]); | |
const [loading, setLoading] = useState(false); | |
const [error, setError] = useState(''); | |
const getJoke = async () => { | |
try { | |
const url = new URL('https://v2.jokeapi.dev/joke/Programming'); | |
const res = await fetch(url, { | |
method: 'GET', | |
headers: {Accept: 'application/json'}, | |
}); | |
if (!res.ok) throw new Error(`Ошибка HTTP: ${res.status}`); | |
return await res.json(); | |
} catch (err) { | |
console.error(err); | |
return null; | |
} | |
}; | |
const fetchJokes = async () => { | |
setLoading(true); | |
setError(''); | |
setJokes([]); | |
const results = []; | |
let attempts = 0; | |
while (results.length < 50 && attempts < 70) { | |
const joke = await getJoke(); | |
if (joke) results.push(joke); | |
attempts++; | |
} | |
if (results.length === 0) { | |
setError('Не удалось загрузить шутки.'); | |
} else { | |
setJokes(results); | |
} | |
setLoading(false); | |
}; | |
return ( | |
<div style={styles.body}> | |
<div style={styles.container}> | |
<h2>Шутки на fetch API</h2> | |
<button style={styles.button} onClick={fetchJokes}> | |
Загрузить 50 шуток | |
</button> | |
{loading && <p>Загрузка шуток...</p>} | |
{error && <p style={styles.error}>{error}</p>} | |
{jokes.map((joke, index) => ( | |
<JokeBox joke={joke} key={index} index={index + 1}/> | |
))} | |
{!loading && jokes.length > 0 && <p>Загрузка завершена!</p>} | |
</div> | |
</div> | |
); | |
}; | |
export default JokeApp; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment