• Jobs
  • About Us
  • professionals
    • Home
    • Jobs
    • Courses and challenges
  • business
    • Home
    • Post vacancy
    • Our process
    • Pricing
    • Assessments
    • Payroll
    • Blog
    • Sales
    • Salary Calculator

0

175
Views
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.

almost 3 years ago · Juan Pablo Isaza
1 answers
Answer question

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

almost 3 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Our process Sales
Legal
Terms and conditions Privacy policy
© 2025 PeakU Inc. All Rights Reserved.

Andres GPT

Recommend me some offers
I have an error