Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

127
Views
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 answers
Answer question

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!