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

171
Vistas
El valor de useState cambia cuando lo llamo desde niño

Estoy creando una aplicación de temporizador creada con ganchos de reacción y una serie de estos temporizadores. No entiendo por qué cambia timerList.

Aquí está el componente padre.

 const [timerList, setTimerList] = useState([]); const removeTimer = () => { console.log("timerList", timerList); }; return ( <div id="main"> {timerList ? timerList.map((child) => child) : null} <div className="add-button before"> <button onClick={() => { const time = new Date(); time.setSeconds(time.getSeconds() + 0); setTimerList((timerList) => [ ...timerList, <FullTimer expiryTimestamp={time} removeTimer={() => { removeTimer(); }} id={window.prompt("Insert timer name") + ` ${timerList.length}`} key={timerList.length} />, ]); }} >

El componente del niño interesado:

 <button onClick={() => { removeTimer(); }} >

El componente secundario es un temporizador personalizado con algo de CSS, y cuando llamo a removeTimer, el valor de timerList (en el componente principal) cambia, cuando debería permanecer igual.

¿Qué me estoy perdiendo?

PD: las etiquetas de los botones no están cerradas porque tengo algún elemento dentro de ellas que usa una fuente increíble

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

0

Nota al margen: en general, se considera una mala práctica almacenar componentes en otro estado de componentes.


Pero ese no es realmente el problema aquí. Dado su código, es un problema de cierre simple .

Este:

 const removeTimer = () => { console.log("timerList", timerList); };

la definición se cierra sobre la timerList actual. Entonces lo registrará , como estaba cuando se asignó removeTimer . Actualmente eso está en cada render. Así que registrará el estado aparentemente un paso atrás . No hay solución para eso, porque así es como funcionan los cierres.

Siempre que realmente desee eliminar un temporizador, cuando se invoque removeTimer , deberá usar la versión de devolución de llamada del actualizador ( setTimerList ) y pasar algún valor de identificación para que pueda eliminar el correcto.

Todo esto sería mucho más simple si siguiera el consejo inicial y no almacenara el componente en el estado, sino que está definiendo propiedades.


El siguiente sería un ejemplo de trabajo (disculpe mi texto mecanografiado):

 import React, { useState } from 'react'; type FullTimerProps = { id: string; expiryTimestamp: Date; removeTimer: () => void; } const FullTimer = ({expiryTimestamp, removeTimer, id}: FullTimerProps): JSX.Element => { return ( <div> <button onClick={removeTimer}>remove</button> {id}: {expiryTimestamp.toLocaleDateString()} </div> ); }; type Timer = { id: string; expiryTimestamp: Date; }; const TimerList = (): JSX.Element => { const [timerList, setTimerList] = useState<Timer[]>([]); const removeTimer = (timer: Timer) => { setTimerList(timerList => timerList.filter(t => t.id !== timer.id)); }; return ( <div id="main"> {timerList.map(timer => ( <FullTimer key={timer.id} id={timer.id} expiryTimestamp={timer.expiryTimestamp} removeTimer={() => removeTimer(timer)} /> ))} <div className="add-button before"> <button onClick={() => setTimerList(timerList => [...timerList, { id: window.prompt('Insert timer name') + ` ${timerList.length}`, expiryTimestamp: new Date() }])} >Add </button> </div> </div> ); };
about 4 years ago · Juan Pablo Isaza Denunciar

0

cambiar este fragmento de código

 setTimerList((timerList) => [ ...timerList, <FullTimer expiryTimestamp={time} removeTimer={() => removeTimer()} id={window.prompt("Insert timer name") + ` ${timerList.length}`} key={timerList.length} />, ]);

a

 timerList.push(<FullTimer expiryTimestamp={time} removeTimer={() => removeTimer()} id={window.prompt("Insert timer name") + ` ${timerList.length}`} key={timerList.length} />); setTimerList([...timerList]);

Solucionado el problema que tienes. Aunque este cambio no se recomienda porque no es un enfoque inmutable, pero soluciona este caso.

ACTUALIZACIÓN: Resultó que duplicó la función removeTimer durante la llamada a setTimerList , lo que provocó que el componente secundario capturara timerList en el momento de la asignación. Que se menciona en https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures?retiredLocale=vi#closure como ha demostrado el Sr. @yoshi

about 4 years ago · Juan Pablo Isaza Denunciar

0

Intenta escribir tu función onclick así

 <button onClick={() => removeTimer()} >

También por aquí

 <FullTimer expiryTimestamp={time} removeTimer={() => removeTimer()}
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