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.

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;