0Pricing
TypeScript Academy · Lección

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

  1. Props y children; controladores de eventos; refs
  2. Estado y reducers; tipado de Context
  3. Genéricos de componentes: introducción
← Volver a TypeScript Academy