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.
Context API
- context
- 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.
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.
Fuentes:
Pensemos en el siguiente caso:
routes/Inicio.jsx
import { useState } from "react";
const Inicio = () => {
const [user, setUser] = useState(false);
return (
<div>
<h1>Inicio</h1>
<h2>{user ? "Conectado" : "Desconectado"}</h2>
{user ? (
<button
className="btn btn-danger"
onClick={() => setUser(false)}
>
Cerrar sesión
</button>
) : (
<button
className="btn btn-primary"
onClick={() => setUser(true)}
>
Iniciar sesión
</button>
)}
</div>
);
};
export default Inicio;
¿Cómo podríamos pasar al usuario al components/Navbar.jsx
?
<nav className="navbar navbar-dark bg-dark">
<div className="container">
<Link to="/">user ?</Link>
<NavLink className="btn btn-sm btn-outline-primary" to="/">
Inicio
</NavLink>
<NavLink className="btn btn-sm btn-outline-primary" to="/blog">
Blog
</NavLink>
<NavLink className="btn btn-sm btn-outline-primary" to="/contacto">
Contacto
</NavLink>
</div>
</nav>
createContext
- 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/UserProvider.jsx
import { createContext, useState } from "react";
export const UserContext = createContext();
const UserProvider = (props) => {
const [user, setUser] = useState(false);
const signIn = () => {
setUser(true);
};
const signOut = () => {
setUser(false);
};
return (
<UserContext.Provider value={{ user, signIn, signOut }}>
{props.children}
</UserContext.Provider>
);
};
export default UserProvider;
index.js
ReactDOM.render(
<BrowserRouter>
<UserProvider>
<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>
</UserProvider>
</BrowserRouter>,
document.getElementById("root")
);
useContext
Acepta un objeto de contexto (el valor devuelto de React.createContext) y devuelve el valor de contexto actual. El valor actual del contexto es determinado por la propiedad value del <MyContext.Provider
> ascendentemente más cercano en el árbol al componente que hace la llamada.
routes/Inicio.jsx
import { useContext } from "react";
import { UserContext } from "../context/UserProvider";
const Inicio = () => {
const { user, signIn, signOut } = useContext(UserContext);
return (
<div>
<h1>Inicio</h1>
<h2>{user ? "Conectado" : "Desconectado"}</h2>
{user ? (
<button className="btn btn-danger" onClick={signOut}>
Cerrar sesión
</button>
) : (
<button className="btn btn-primary" onClick={signIn}>
Iniciar sesión
</button>
)}
</div>
);
};
export default Inicio;
components/Navbar.jsx
import { UserContext } from "../context/UserProvider";
const Navbar = () => {
const { user } = useContext(UserContext);
return (
<nav className="navbar navbar-dark bg-dark">
<div className="container">
<Link to="/">
{user ? "Juanito" : "SinConexión"}
</Link>
Extra Ruta Protegida
routes/RutaProtegida.jsx
const RutaProtegida = () => {
return (
<div>
<h1>Solo usuarios registrados pueden ver esta página</h1>
</div>
);
};
export default RutaProtegida;
components/RequireAuth.jsx
import { useContext } from "react";
import { Navigate } from "react-router-dom";
import { UserContext } from "../context/UserProvider";
const RequireAuth = ({ children }) => {
const { user } = useContext(UserContext);
if (!user) {
return <Navigate to="/" />;
}
return children;
};
export default RequireAuth;
index.js
ReactDOM.render(
<BrowserRouter>
<UserProvider>
<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="protegida"
element={
<RequireAuth>
<RutaProtegida />
</RequireAuth>
}
/>
<Route path="*" element={<NoEncontrada />} />
</Route>
</Routes>
</UserProvider>
</BrowserRouter>,
document.getElementById("root")
);
routes/Inicio.jsx
import { useContext } from "react";
import { UserContext } from "../context/UserProvider";
import { Link } from "react-router-dom";
const Inicio = () => {
const { user, signIn, signOut } = useContext(UserContext);
return (
<div>
<h1>Inicio</h1>
<h2>{user ? "Conectado" : "Desconectado"}</h2>
{user ? (
<>
<button className="btn btn-danger" onClick={signOut}>
Cerrar sesión
</button>
<Link to="/protegida" className="btn btn-warning">
Protegida
</Link>
</>
) : (
<button className="btn btn-primary" onClick={signIn}>
Iniciar sesión
</button>
)}
</div>
);
};
export default Inicio;