<div id="root">
#root {
display: flex;
flex-direction: column;
}
.spinner-container {
display: flex;
align-items: center;
justify-content: center;
}
.spinner {
color: #000;
display: inline-block;
width: 20px;
height: 20px;
animation: spinner .75s linear infinite;
border: 4px solid #000;
border-bottom-color: transparent;
border-radius: 100%;
background: 0 0;
}
@keyframes spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
const Spinner = () => {
return (
<div className="spinner-container">
<span className="spinner"/>
</div>
)
}
const useTodos = () => {
const [page, setPage] = React.useState(1);
const [todos, setTodos] = React.useState([]);
React.useEffect(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/');
const todos = await response.json();
const offset = (page - 1) * 20;
setTodos(todos.slice(offset > 0 ? offset -1 : 0, 20));
}, [page]);
return { todos, page, setPage };
}
const Todos = () => {
const {todos, page} = useTodos();
return todos.length > 0 ? <p>Hello, world! {todos.length} todos, page {page}!</p> : <Spinner/>
}
const TodosPaginate = () => {
const {todos, page, setPage} = useTodos();
return (
<div>
<p>Page: {page}</p>
{ page > 1 ? <button onClick={() => setPage(page-1)}>Prev ({page-1})</button> : null }
{ page < 10 ? <button onClick={() => setPage(page+1)}>Next ({page+1})</button> : null }
</div>
);
}
ReactDOM.render(<><Todos/><TodosPaginate/></>, document.getElementById("root"));
View Compiled
This Pen doesn't use any external CSS resources.