Skip to content

React Context API

En esta sección aprenderemos a trabajar con Context API.

⭐ Videos Premium ⭐

Esta sección es parte del curso en Udemy. Si quieres acceder a ella, puedes comprar el curso en Udemy: React + Firebase by bluuweb.

O bien también puedes visualizar los videos siendo miembro en Youtube. Accede a miembros del canal aquí y accede a los videos de esta sección.

Proyecto Final

WARNING

Es necesario ver la sección anterior donde trabajamos con React Router Dom v6.

Contex API

  • contex API
  • Hook useContext
  • Context provee una forma de pasar datos a través del árbol de componentes sin tener que pasar props manualmente en cada nivel.
  • Context está diseñado para compartir datos que pueden considerarse “globales” para un árbol de componentes en React, como el usuario autenticado actual, el tema o el idioma preferido.
  • Si trabajas con diferentes vistas estas no estarán anidadas, por ende Context proporciona una solución.

global props propagation

Redux vs Context

  • Redux proporciona un conjunto de herramientas completo para administrar el estado:
    • Viene con un depurador que viaja en el tiempo.
    • Proporciona una API de middleware que le brinda acceso a herramientas como redux-sagas.
    • Sus enlaces de React evitan muchos renderizados innecesarios.

Como puede ver, el contexto no reemplaza a Redux. El contexto no le permitirá viajar en el tiempo con depuración, middleware configurable.

Context es una forma de obtener datos de un lugar a otro. Si desea una herramienta que lo ayude a administrar su estado, Redux es una excelente opción.

Template Base

sh
npm create vite@latest .
npm install
npm install react-router-dom@6.4

CreateContext

  • CreateContext
  • useContext
  • Crea un objeto Context. Cuando React renderiza un componente que se suscribe a este objeto Context, este leerá el valor de contexto actual del Provider más cercano en el árbol.
  • Cada objeto Context viene con un componente Provider de React que permite que los componentes que lo consumen se suscriban a los cambios del contexto.
  • El componente Provider acepta una prop value que se pasará a los componentes consumidores que son descendientes de este Provider.

context/UserContext.jsx

jsx
import { createContext, useContext } from "react";

export const UserContext = createContext(false);

export const useUserContext = () => useContext(UserContext);

components/Navbar.js

jsx
import { NavLink } from "react-router-dom";

import { useUserContext } from "../context/UserContext";

const Navbar = () => {
    console.log(useUserContext());

    return (
        <nav>
            <NavLink to="/">Home</NavLink>
            <NavLink to="/dashboard">Dashboard</NavLink>
        </nav>
    );
};

export default Navbar;

Provider

  • Provider
  • Cada objeto Context viene con un componente Provider de React que permite que los componentes que lo consumen se suscriban a los cambios del contexto.
  • El componente Provider acepta una prop value que se pasará a los componentes consumidores que son descendientes de este Provider.

context/UserContext.jsx

jsx
import { createContext, useContext, useState } from "react";

export const UserContext = createContext();

const UserProvider = ({ children }) => {
    const [user, setUser] = useState(null);

    return (
        <UserContext.Provider value={{ user, setUser }}>
            {children}
        </UserContext.Provider>
    );
};

export default UserProvider;

export const useUserContext = () => useContext(UserContext);

main.jsx

jsx
import UserProvider from "./context/UserContext";

ReactDOM.createRoot(document.getElementById("root")).render(
    <React.StrictMode>
        <UserProvider>
            <RouterProvider router={router} />
        </UserProvider>
    </React.StrictMode>
);

Navbar.jsx

jsx
import { NavLink } from "react-router-dom";

import { useUserContext } from "../context/UserContext";

const Navbar = () => {
    const { user, setUser } = useUserContext();

    return (
        <nav>
            <NavLink to="/">Home</NavLink>
            {user && (
                <>
                    <NavLink to="/dashboard">Dashboard</NavLink>
                    <button onClick={() => setUser(null)}>Logout</button>
                </>
            )}
        </nav>
    );
};

export default Navbar;

Home.jsx

jsx
import { useUserContext } from "../context/UserContext";

const Home = () => {
    const { user, setUser } = useUserContext();

    return (
        <>
            <h1>Home</h1>
            {!user && (
                <button onClick={() => setUser({ name: "John Doe" })}>
                    Login
                </button>
            )}
        </>
    );
};

export default Home;

Private Rutes

Las rutas protegidas son rutas que solo se pueden acceder si el usuario está autenticado. Si el usuario no está autenticado, se redirige a la página de inicio de sesión.

LayoutPrivate.jsx

jsx
import { useEffect } from "react";
import { Outlet, useNavigate } from "react-router-dom";
import { useUserContext } from "../context/UserContext";

const LayoutPrivate = () => {
    const { user } = useUserContext();
    const navigate = useNavigate();

    useEffect(() => {
        if (!user) {
            navigate("/");
        }
    }, [user]);

    return <Outlet />;
};

export default LayoutPrivate;

Alternativa Navigate

jsx
import { Outlet, Navigate } from "react-router-dom";
import { useUserContext } from "../context/UserContext";

const LayoutPrivate = () => {
    const { user } = useUserContext();

    return <>{user ? <Outlet /> : <Navigate to="/" />}</>;
};

export default LayoutPrivate;

Dashboard.jsx

jsx
import { useUserContext } from "../context/UserContext";

const Dashboard = () => {
    const { user } = useUserContext();

    return (
        <>
            <h1>Dashboard</h1>
            <p>{user?.name}</p>
        </>
    );
};

export default Dashboard;

Home.jsx

jsx
import { useNavigate } from "react-router-dom";
import { useUserContext } from "../context/UserContext";

const Home = () => {
    const { user, setUser } = useUserContext();

    const navigate = useNavigate();

    const handleClickLogin = () => {
        setUser({ name: "John Doe" });
        navigate("/dashboard");
    };

    return (
        <>
            <h1>Home</h1>
            {!user && <button onClick={handleClickLogin}>Login</button>}
        </>
    );
};

export default Home;