Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

252
Vistas
El reductor de React devuelve un estado inesperado que no es consistente con el valor registrado

Creé un reductor que incrementa un UID global en cada envío con el increment de acción. El valor inicial del UID es 0 .

Expectativa :

Esperaba que el UID se incrementara en 1 en cada envío.

realidad :

Los incrementos de UID por 2 y el estado registrado son inconsistentes con el valor del estado real.

Mi componente:

 import React, { useReducer } from "react" let uid = 0 function nextUID() { uid = uid + 1 return uid } function reducer(state, action) { switch (action.type) { case "increment": const uid = nextUID() const newState = `current UID is ${uid}!` console.log(newState) return newState default: return state } } function TestComponent() { const [state, dispatch] = useReducer(reducer, "not clicked yet") return <button onClick={() => dispatch({ type: "increment" })}>{state}</button> } export default TestComponent

Salida :

número Clics Etiqueta de botón Salida de consola
0 aún no se ha hecho clic
1 ¡El UID actual es 1! ¡El UID actual es 1!
2 ¡El UID actual es 3! ¡El UID actual es 2!
3 ¡El UID actual es 5! ¡El UID actual es 4!

Pregunta :

¡Cómo es posible que la etiqueta del botón sea current UID is 3! ¡mientras que la salida de la consola para el cambio de estado era current UID is 2! ? ¿Es posible que react llame al reductor varias veces y descarte la salida de la consola la segunda vez?

Información adicional :

  • También traté de usar const uidRef = useRef(0) en TestComponent con un reductor anónimo que incrementa uidRef.current . El comportamiento era el mismo.
  • También intenté agregar una salida de consola a nextUID() . El resultado fue new uid 1; new uid 2; new uid 4; ...

Gracias.

about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

Muy bien , StrictMode te está molestando, pero en el buen sentido. El código que ha escrito no es deseable según React . StrictMode llama a su reducer dos veces para eliminar cualquier efecto secundario . En su caso, la implementación de incrementar uid es uno de esos efectos secundarios .

(Simplemente hacer console.log no le mostraría que se está llamando a reducer dos veces ya que React lo silencia para la segunda llamada desde 17.0 . Así que he usado una función de log para referirme al mismo console.log );

Aquí está tu código :-

 import React, { useReducer } from "react"; const log = console.log; let uid = 0; function nextUID() { uid = uid + 1; return uid; } function reducer(state, action) { switch (action.type) { case "increment": log("called reducer"); const uid = nextUID(); const newState = `current UID is ${uid}!`; console.log(newState); return newState; default: return state; } } function TestComponent() { const [state, dispatch] = useReducer(reducer, "not clicked yet"); return ( <button onClick={() => dispatch({ type: "increment" })}>{state}</button> ); } export default TestComponent;

Edite React useReducer dos veces en modo estricto

Ahora su código original funcionaría bien en producción porque el reductor se llamaría solo una vez (ya que las producciones no tienen un componente de contenedor de modo estricto ), pero no es una buena práctica.

A continuación se muestra otra implementación en la que el estado no se muta directamente y, por lo tanto, entre dos llamadas al reductor, el estado anterior sigue siendo el mismo y el siguiente valor de incremento es consistente. Si mutaste el estado directamente como state.val += 1 , verías el mismo comportamiento que tu ejemplo en modo estricto .

 import React, { useReducer } from "react"; const log = console.log; function reducer(state, action) { switch (action.type) { case "increment": log("called reducer"); const nextStateVal = state.val + 1; return { ...state, text: `current UID is ${nextStateVal}`, val: nextStateVal }; default: return state; } } function TestComponent() { const [state, dispatch] = useReducer(reducer, { text: "not clicked yet", val: 0 }); return ( <button onClick={() => dispatch({ type: "increment" })}> {state.text} </button> ); } export default TestComponent;

Editar React useReducer modo estricto forma correcta

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda