# 16 React Router v6

En esta sección aprenderemos a trabajar con rutas en nuestra aplicación con React.

# Proyecto Final

# Router v6

  • react router v6 (opens new window)
  • React Router es una biblioteca de enrutamiento del lado del servidor y del cliente con todas las funciones para React.
  • React Router se ejecuta en cualquier lugar donde se ejecute React; en la web, en el servidor con node.js y en React Native.
npx create-react-app router-tutorial
cd router-tutorial
npm i react-router-dom@6
npm start

# Conectar URL

Lo primero es lo primero, queremos conectar su aplicación a la URL del navegador: importarla BrowserRouter y renderizarla alrededor de toda su aplicación.

index.js

import React from "react";
import ReactDOM from "react-dom";

import { BrowserRouter } from "react-router-dom";

import App from "./App";

ReactDOM.render(
    <BrowserRouter>
        <App />
    </BrowserRouter>,
    document.getElementById("root")
);

Navbar.jsx

import { Link } from "react-router-dom";

const Navbar = () => {
    return (
        <nav className="navbar navbar-dark bg-dark">
            <div className="container">
                <Link className="btn btn-outline-primary" to="/">
                    Inicio
                </Link>
                <Link className="btn btn-outline-primary" to="/blog">
                    Blog
                </Link>
                <Link className="btn btn-outline-primary" to="/contacto">
                    Contacto
                </Link>
            </div>
        </nav>
    );
};

export default Navbar;

App.jsx

import Navbar from "./components/Navbar";

const App = () => {
    return (
        <div>
            <Navbar />
            <div className="container">
                <h1>App</h1>
            </div>
        </div>
    );
};

export default App;

# Agregar Rutas

  • src/routes/Blog.jsx
  • src/routes/Contacto.jsx
  • src/routes/Inicio.jsx

index.jsx

import React from "react";
import ReactDOM from "react-dom";

import "bootstrap/dist/css/bootstrap.min.css";
import { BrowserRouter, Routes, Route } from "react-router-dom";

import App from "./App";
import Blog from "./routes/Blog";
import Contacto from "./routes/Contacto";

ReactDOM.render(
    <BrowserRouter>
        <Routes>
            <Route path="/" element={<App />} />
            <Route path="blog" element={<Blog />} />
            <Route path="contacto" element={<Contacto />} />
        </Routes>
    </BrowserRouter>,
    document.getElementById("root")
);

# Rutas anidadas

  • Es posible que haya notado al hacer clic en los enlaces que el diseño Appdesaparece.
  • Cuando las rutas tienen niños, hace dos cosas:
    • Anida las URL ( "/" + "blog" y "/" + "contacto")
    • Anidará los componentes de la interfaz de usuario para el diseño compartido cuando la ruta secundaria coincida

Paso 1:

ReactDOM.render(
    <BrowserRouter>
        <Routes>
            <Route path="/" element={<App />}>
                <Route path="blog" element={<Blog />} />
                <Route path="contacto" element={<Contacto />} />
            </Route>
        </Routes>
    </BrowserRouter>,
    document.getElementById("root")
);

Paso 2: App.jsx

import { Outlet } from "react-router";
import Navbar from "./components/Navbar";

const App = () => {
    return (
        <div>
            <Navbar />
            <div className="container">
                <Outlet />
            </div>
        </div>
    );
};

export default App;

# Ruta indice





 








ReactDOM.render(
    <BrowserRouter>
        <Routes>
            <Route path="/" element={<App />}>
                <Route index element={<Inicio />} />
                <Route path="blog" element={<Blog />} />
                <Route path="contacto" element={<Contacto />} />
            </Route>
        </Routes>
    </BrowserRouter>,
    document.getElementById("root")
);
  • Observe que tiene el index prop en lugar de path.
  • Eso es porque la ruta del índice comparte la ruta del padre.
  • Las rutas de índice coinciden cuando una ruta principal coincide, pero ninguna de las otras secundarias coincide.
  • Las rutas de índice son la ruta secundaria predeterminada para una ruta principal.
  • Las rutas de índice se representan cuando el usuario aún no ha hecho clic en uno de los elementos de una lista de navegación.
import { NavLink } from "react-router-dom";

const Navbar = () => {
    return (
        <nav className="navbar navbar-dark bg-dark">
            <div className="container">
                <NavLink className="btn btn-outline-primary" to="/">
                    Inicio
                </NavLink>
                <NavLink className="btn btn-outline-primary" to="/blog">
                    Blog
                </NavLink>
                <NavLink className="btn btn-outline-primary" to="/contacto">
                    Contacto
                </NavLink>
            </div>
        </nav>
    );
};

export default Navbar;

# 404

import { Link } from "react-router-dom";

const NoEncontrada = () => {
    return (
        <div>
            <h1>404</h1>
            <Link to="/" className="btn btn-outline-dark">
                Inicio
            </Link>
        </div>
    );
};

export default NoEncontrada;







 






ReactDOM.render(
    <BrowserRouter>
        <Routes>
            <Route path="/" element={<App />}>
                <Route index element={<Inicio />} />
                <Route path="blog" element={<Blog />} />
                <Route path="contacto" element={<Contacto />} />
                <Route path="*" element={<NoEncontrada />} />
            </Route>
        </Routes>
    </BrowserRouter>,
    document.getElementById("root")
);

# Parámetros

hooks/useFetch.js

import { useEffect, useState } from "react";

export const useFetch = (url) => {
    const [data, setData] = useState([]);
    const [error, setError] = useState("");
    const [loading, setLoading] = useState(false);

    useEffect(() => {
        setLoading(true);
        fetch(url)
            .then((res) => res.json())
            .then((data) => setData(data))
            .catch((e) => setError("Ocurrió un error"))
            .finally(() => setLoading(false));
    }, [url]);

    return { data, error, loading };
};

Blog.jsx

import { Link } from "react-router-dom";
import { useFetch } from "../hooks/useFetch";

const Blog = () => {
    const { data, error, loading } = useFetch(
        "https://jsonplaceholder.typicode.com/posts"
    );

    if (loading) {
        return <h1>Loading...</h1>;
    }

    if (error !== "") {
        return <h1>{error}</h1>;
    }

    return (
        <div>
            <h1>Blog</h1>
            {data.map((item) => (
                <h4 key={item.id}>
                    <Link to={`/blog/${item.id}`}>
                        {item.id} - {item.title}
                    </Link>
                </h4>
            ))}
        </div>
    );
};

export default Blog;






 








ReactDOM.render(
    <BrowserRouter>
        <Routes>
            <Route path="/" element={<App />}>
                <Route index element={<Inicio />} />
                <Route path="blog" element={<Blog />} />
                <Route path="blog/:id" element={<Post />} />
                <Route path="contacto" element={<Contacto />} />
                <Route path="*" element={<NoEncontrada />} />
            </Route>
        </Routes>
    </BrowserRouter>,
    document.getElementById("root")
);

Post.jsx

import { useParams } from "react-router";
import { useFetch } from "../hooks/useFetch";

const Post = () => {
    let params = useParams();

    const { data, error, loading } = useFetch(
        "https://jsonplaceholder.typicode.com/posts/" + params.id
    );

    if (loading) {
        return <h1>Loading...</h1>;
    }

    if (error !== "") {
        return <h1>{error}</h1>;
    }

    return (
        <div>
            <h1>
                {data.id} - {data.title}
            </h1>
            <p>{data.body}</p>
        </div>
    );
};

export default Post;

# Parámetros de búsqueda

  • React Router hace que sea fácil de leer y manipular los parámetros de búsqueda con useSearchParams
  • Funciona de manera muy similar, React.useState() pero almacena y establece el estado en los parámetros de búsqueda de URL en lugar de en la memoria.

Blog.jsx

let [searchParams, setSearchParams] = useSearchParams();

useEffect(() => {
    // http://localhost:3000/blog?nombre=juan
    console.log(searchParams.get("nombre"));
}, [searchParams]);

Blog.jsx

import { Link, useSearchParams } from "react-router-dom";
import { useFetch } from "../hooks/useFetch";

const Blog = () => {
    let [searchParams, setSearchParams] = useSearchParams();

    const { data, error, loading } = useFetch(
        "https://jsonplaceholder.typicode.com/posts"
    );

    if (loading) {
        return <h1>Loading...</h1>;
    }

    if (error !== "") {
        return <h1>{error}</h1>;
    }

    const handleChange = (e) => {
        let filter = e.target.value;
        if (filter) {
            setSearchParams({ filter });
        } else {
            setSearchParams({});
        }
    };

    return (
        <div>
            <h1>Blog</h1>
            <input
                className="form-control mb-2"
                type="text"
                value={searchParams.get("filter") || ""}
                onChange={handleChange}
            />
            {data
                .filter((item) => {
                    let filter = searchParams.get("filter");
                    if (!filter) return true;
                    let name = item.title.toLowerCase();
                    return name.startsWith(filter.toLowerCase());
                })
                .map((item) => (
                    <h4 key={item.id}>
                        <Link to={`/blog/${item.id}`}>
                            {item.id} - {item.title}
                        </Link>
                    </h4>
                ))}
        </div>
    );
};

export default Blog;

# Netlify + queryParams

/* /index.html 200
npm run build

Subir a netlify 🎉 https://www.netlify.com/ (opens new window)

Last Updated: 6/4/2022, 12:52:28