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

138
Vistas
Misma lógica pero diferente comportamiento en 'clase' y en 'componente funcional'

Intenté traducir un código de ejemplo de class a functional component y enfrenté el problema.

el archivo de destino está en components/Wheel/index.js

Función clave que causa el problema

 const selectItem = () => { if (selectedItem === null) { const selectedItem = Math.floor(Math.random() * items.length); console.log(selectedItem); setSelectedItem(selectedItem); } else { setSelectedItem(null); let t= setTimeout(() => { selectItem() }, 500); clearTimeout(t); } };

La primera vez es normal, a partir de la segunda vez, se necesitan 2 clics para que la rueda gire. Tuve que agregar clearTimeout() o se generó un bucle infinito , pero no sucede lo mismo en el original.

Ejemplo de trabajo original en class

Demostración de Codesandbox

Mi versión en functional component .

Mi version

Gracias.

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

0

Qué excelente matiz de ganchos que has descubierto. Cuando llama a selectItem en el tiempo de espera, el valor de selectedItem que se captura en el ámbito léxico es el último valor (no nulo).

Hay dos respuestas, una respuesta simple y una mejor respuesta de trabajo.

La respuesta simple es que puede lograrlo simplemente separando las funciones: https://codesandbox.io/s/spinning-wheel-game-forked-cecpi

Se parece a esto:

 const doSelect = () => { setSelectedItem(Math.floor(Math.random() * items.length)); }; const selectItem = () => { if (selectedItem === null) { doSelect(); } else { setSelectedItem(null); setTimeout(doSelect, 500); } };

Ahora, sigue leyendo si te atreves.

La respuesta complicada corrige la solución del problema si items.length puede cambiar entre el momento en que se configura un temporizador y se dispara:

https://codesandbox.io/s/spinning-wheel-game-bifurcado-wmeku

Volver a renderizar (es decir, configurar el estado) en un tiempo de espera causa complejidad: si el componente se volvió a renderizar entre el tiempo de espera, entonces su devolución de llamada podría haber capturado accesorios/estado "obsoletos". Así que están pasando muchas cosas aquí. Intentaré describirlo lo mejor que pueda:

 const [selectedItem, setSelectedItem] = useState(null); // we're going to use a ref to store our timer const timer = useRef(); const { items } = props; // this is just the callback that performs a random select // you can see it is dependent on items.length from props const doSelect = useCallback(() => { setSelectedItem(Math.floor(Math.random() * items.length)); }, [items.length]); // this is the callback to setup a timeout that we do // after the user has clicked a "second" time. // it is dependent on doSelect const doTimeout = useCallback(() => { timer.current = setTimeout(() => { doSelect(); timer.current = null; }, 500); }, [doSelect]); // Here's the tricky thing: if items.length changes in between // the time we rerender and our timer fires, then the timer callback will have // captured a stale value for items.length. // The way we fix this is by using this effect. // If items.length changes and there is a timer in progress we need to: // 1. clear it // 2. run it again // // In a perfect world we'd be capturing the amount of time remaining in the // timer and fire it exactly (which requires another ref) // feel free to try and implement that! useEffect(() => { if (!timer.current) return; clearTimeout(timer.current); doTimeout(); // it's safe to ignore this warning because // we know exactly what the dependencies are here }, [items.length, doTimeout]); const selectItem = () => { if (selectedItem === null) { doSelect(); } else { setSelectedItem(null); doTimeout(); } };
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