Estado y reducers; tipado de Context
Gestione el estado de los componentes con useState y useReducer, y eleve después el estado a un Context tipado mediante un hook personalizado seguro.
Estado y reducers; tipado de Context es una lección gratuita de TypeScript Academy en CoddyKit. Esta es la lección 2 de 3. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de TypeScript Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de TypeScript Academy incluye 3 lecciones en total.
Introducción
Objetivo: Empiece con estado local (useState), pase a un reducer tipado (useReducer) y, después, eleve el estado a un Context tipado con un hook personalizado seguro.
- Modele explícitamente el estado y las acciones
- Prefiera las uniones discriminadas
- Proteja el acceso a Context
useState tipado
Anote el estado con un tipo concreto (por ejemplo, number). Use la forma de actualización para evitar cierres obsoletos en actualizaciones rápidas.
import React, { useState } from "react"
export default function Counter() {
const [count, setCount] = useState<number>(0)
const inc = () => setCount(c => c + 1)
const dec = () => setCount(c => c - 1)
return (
<div style={{ display: "grid", gap: 8 }}>
<div>Count: {count}</div>
<div style={{ display: "flex", gap: 8 }}>
<button onClick={inc}>+1</button>
<button onClick={dec}>-1</button>
</div>
</div>
)
}useReducer tipado
Modele Action como una unión discriminada. El switch sigue siendo exhaustivo; las cargas tienen un tipo distinto en cada rama.
import React, { useReducer } from "react"
type State = { count: number }
type Action =
| { type: "inc" }
| { type: "add"; by: number }
| { type: "reset" }
function reducer(s: State, a: Action): State {
switch (a.type) {
case "inc": return { count: s.count + 1 }
case "add": return { count: s.count + a.by }
case "reset": return { count: 0 }
}
}
export default function App() {
const [state, dispatch] = useReducer(reducer, { count: 0 })
return (
<div style={{ display: "grid", gap: 8 }}>
<div>Count: {state.count}</div>
<button onClick={() => dispatch({ type: "inc" })}>+1</button>
<button onClick={() => dispatch({ type: "add", by: 5 })}>+5</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
</div>
)
}Context y hook
Cree Context<T | null> y exponga después useX, que lance un error si el valor es null. Los consumidores seguirán siendo sencillos y estarán bien tipados.
import React, { createContext, useContext, useReducer } from "react"
type State = { count: number }
type Action = { type: "inc" } | { type: "add"; by: number } | { type: "reset" }
function reducer(s: State, a: Action): State {
switch (a.type) {
case "inc": return { count: s.count + 1 }
case "add": return { count: s.count + a.by }
case "reset": return { count: 0 }
}
}
type Ctx = { state: State; dispatch: React.Dispatch<Action> }
const CounterCtx = createContext<Ctx | null>(null)
export function useCounter() {
const ctx = useContext(CounterCtx)
if (!ctx) throw new Error("useCounter must be used within CounterProvider")
return ctx
}
export function CounterProvider({ children }: { children: React.ReactNode }) {
const [state, dispatch] = useReducer(reducer, { count: 0 })
return <CounterCtx.Provider value={{ state, dispatch }}>{children}</CounterCtx.Provider>
}
export default function App() {
return (
<CounterProvider>
<Inner />
</CounterProvider>
)
}
function Inner() {
const { state, dispatch } = useCounter()
return (
<div style={{ display: "grid", gap: 8 }}>
<div>Count: {state.count}</div>
<button onClick={() => dispatch({ type: "inc" })}>+1</button>
</div>
)
}Patrón de Context y reducer
Separe la lectura y el envío de acciones entre los componentes. Provider envuelve a los hijos y proporciona el estado y dispatch tipados.
import React from "react"
import { CounterProvider, useCounter } from "./ctx"
function Controls() {
const { dispatch } = useCounter()
return (
<div style={{ display: "flex", gap: 8 }}>
<button onClick={() => dispatch({ type: "inc" })}>+1</button>
<button onClick={() => dispatch({ type: "add", by: 10 })}>+10</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
</div>
)
}
function View() {
const { state } = useCounter()
return <div>Count: {state.count}</div>
}
export default function App() {
return (
<CounterProvider>
<div style={{ display: "grid", gap: 8 }}>
<View />
<Controls />
</div>
</CounterProvider>
)
}Buenas prácticas
Buenas prácticas:
- Mantenga el estado mínimo y derive el resto.
- Prefiera las uniones discriminadas para las acciones.
- Proteja el acceso a Context mediante un hook personalizado.
Comprobación del tipado de Context
Comprobación rápida: ¿cuál es una forma segura de tipar un Context de React?
Resumen
Resumen: Empiece con useState, modele las transiciones con useReducer y eleve el estado compartido a un Context tipado protegido por un hook personalizado.
Preguntas frecuentes
¿La lección «Estado y reducers; tipado de Context» es gratis?
Sí — el texto completo de «Estado y reducers; tipado de Context» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de TypeScript Academy, actualiza a CoddyKit PRO. El curso de TypeScript Academy incluye 3 lecciones en total.
¿Qué aprenderé en «Estado y reducers; tipado de Context»?
Gestione el estado de los componentes con useState y useReducer, y eleve después el estado a un Context tipado mediante un hook personalizado seguro. Practicas TypeScript Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar TypeScript Academy?
No se requiere experiencia previa. TypeScript Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 3.
¿Cuánto tiempo toma la lección «Estado y reducers; tipado de Context»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de TypeScript Academy?
Sí. Cada lección de TypeScript Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Props y children; controladores de eventos; refs
- Estado y reducers; tipado de Context
- Genéricos de componentes: introducción