npm create vite@latest
npm install
npm install react-router-dom axios
π src
β£ π components
β β£ π Navbar.jsx
β β£ π PostForm.jsx
β β£ π PostList.jsx
β β£ π PostItem.jsx
β£ π pages
β β£ π Home.jsx
β β£ π CreatePost.jsx
β β£ π EditPost.jsx
β β£ π NotFound.jsx
β£ π styles
β β£ π styles.css
β£ π App.jsx
β£ π index.js
π App.jsx
import './App.css'
import { BrowserRouter, Route, Routes } from 'react-router-dom'
import Home from './pages/Home'
import CreatePost from './pages/CreatePost'
import EditPost from './pages/EditPost'
import Navbar from './components/Navbar'
function App() {
return (
<>
<BrowserRouter>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/create" element={<CreatePost />} />
<Route path="/edit/:id" element={<EditPost />} />
</Routes>
</BrowserRouter>
</>
)
}
export default App
π components/Navbar.jsx
import { Link } from "react-router-dom";
function Navbar() {
return (
<nav className="navbar">
<h1>CRUD React</h1>
<Link to="/">Inicio</Link>
<Link to="/create">Crear Post</Link>
</nav>
);
}
export default Navbar;
π styles/styles.css (para los estilos)
.navbar {
display: flex;
justify-content: space-between;
padding: 15px;
background-color: #333;
color: white;
}
.navbar a {
color: white;
text-decoration: none;
margin: 0 10px;
}
π pages/Home.jsx
import { useState, useEffect } from "react";
import PostList from "../components/PostList";
function Home() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts?_limit=10")
.then(response => response.json())
.then(data => {
setPosts(data);
setLoading(false);
});
}, []);
return (
<div>
<h2>Lista de Posts</h2>
{loading ? <p>Cargando posts...</p> : <PostList posts={posts} />}
</div>
);
}
export default Home;
π components/PostList.jsx
import PostItem from "./PostItem";
function PostList({ posts }) {
return (
<div>
{posts.map(post => (
<PostItem key={post.id} post={post} />
))}
</div>
);
}
export default PostList;
π components/PostItem.jsx
import { Link } from 'react-router-dom'
import PropTypes from 'prop-types'
function PostItem({ post }) {
return (
<div className="post">
<h3>{post.title}</h3>
<p>{post.body}</p>
<Link to={`/edit/${post.id}`}>Editar</Link>
</div>
)
}
PostItem.propTypes = {
post: PropTypes.shape({
title: PropTypes.string.isRequired,
body: PropTypes.string.isRequired,
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
.isRequired,
}).isRequired,
}
export default PostItem
π pages/CreatePost.jsx
import { useState } from "react";
import { useNavigate } from "react-router-dom";
function CreatePost() {
const [title, setTitle] = useState("");
const [body, setBody] = useState("");
const navigate = useNavigate();
const handleSubmit = (e) => {
e.preventDefault();
fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
body: JSON.stringify({ title, body }),
headers: { "Content-Type": "application/json" }
})
.then(response => response.json())
.then(() => navigate("/"));
};
return (
<div>
<h2>Crear un nuevo Post</h2>
<form onSubmit={handleSubmit}>
<input value={title} onChange={e => setTitle(e.target.value)} placeholder="TΓtulo" />
<textarea value={body} onChange={e => setBody(e.target.value)} placeholder="Cuerpo" />
<button type="submit">Crear</button>
</form>
</div>
);
}
export default CreatePost;
π 8. Editar un post (useParams)
π pages/EditPost.jsx
import { useState, useEffect } from "react";
import { useParams, useNavigate } from "react-router-dom";
function EditPost() {
const { id } = useParams();
const navigate = useNavigate();
const [title, setTitle] = useState("");
const [body, setBody] = useState("");
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/posts/${id}`)
.then(response => response.json())
.then(data => {
setTitle(data.title);
setBody(data.body);
});
}, [id]);
const handleSubmit = (e) => {
e.preventDefault();
fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
method: "PUT",
body: JSON.stringify({ title, body }),
headers: { "Content-Type": "application/json" }
})
.then(() => navigate("/"));
};
return (
<div>
<h2>Editar Post</h2>
<form onSubmit={handleSubmit}>
<input value={title} onChange={e => setTitle(e.target.value)} placeholder="Nuevo tΓtulo" />
<textarea value={body} onChange={e => setBody(e.target.value)} placeholder="Nuevo cuerpo" />
<button type="submit">Actualizar</button>
</form>
</div>
);
}
export default EditPost;