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

217
Vistas
Coincidencia del intervalo setState con animación css

Estoy rotando los elementos en una matriz de imágenes dentro de un intervalo de 5 segundos. Luego tengo una animación css con componentes con estilo que facilita las imágenes de la galería con un desvanecimiento que ocurre en el mismo intervalo de tiempo.

 const fadeIn = keyframes` 5%, 95% { opacity: 1 } 100% { opacity: 0 } ` export const Gallery = styled.div<{ lapse: number }>` position: relative; margin: 0 auto; max-width: 1064px; opacity: 0; animation: ${fadeIn} ease-in-out ${({ lapse }) => `${lapse}s`} infinite; `

El problema es que cuando cambio el state , aunque al principio parece estar sincronizado, finalmente el setState tarda un poco más.

 import React, { useState, useEffect } from 'react' const [images, setImages] = useState<string[]>([]) // Time in seconds for each image swap, fading in between const lapse = 5 ... useEffect(() => { // Clone the images array const imgs = [...images] // Time interval same as css animation to fade in const interval = setInterval(() => { // Take the first element and put it at the end imgs.push(...imgs.splice(0, 1)) // Update the state, this seems to desync as time passes setImages(imgs) }, lapse * 1000) return () => clearInterval(interval) }, [images]) return ( <Gallery lapse={lapse}> <Portal> <img src={imgs/${images[0]}`} </Portal> <Thumbnails> <Thumbwrapper> <img src={imgs/${images[1]}`} </Thumbwrapper> <Thumbwrapper> <img src={imgs/${images[2]}`} </Thumbwrapper> </Thumbnails> </Gallery> )

¿Hay alguna manera de asegurarme de que el intercambio se realice sin problemas?

ingrese la descripción de la imagen aquí

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

0

Haga que la clase de componente se base,

 constructor(props) { super(props); this.state = { interval: null, images: ["1.jpg", "2.jpg", "3.jpg"], timeChanged: null }; } // setInterval when component is mounted componentDidMount() { var interval = setInterval(()=> { // use callback argument for setState // when new value (images) depends on old value this.setState((state)=>({ timeChanged: (new Date()).toString(), images: state.images.slice(1).concat(state.images[0]) // add 1st img at the end }); }, 3000); this.setState({interval: interval}); } // clearInterval before component is unmounted componentWillUnmount() { clearInterval(this.state.interval); }

Cuando el estado se actualiza usando su valor anterior, se debe usar el argumento de devolución de llamada.
(Ver https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous )

slice devuelve una parte de una matriz.

También vea cómo actualizar matrices de estado en React .

Si aún desea utilizar ganchos. Simplemente llame a setImages con (images)=>images.slice(1).concat(images[0]) .
No estoy seguro de dónde debería estar clearTimeout cuando se usan ganchos.

about 4 years ago · Juan Pablo Isaza Denunciar

0

Sería genial si pudiéramos tener un ejemplo en codesandbox. También me gustaría preguntarte, tal vez me estoy perdiendo algo, pero ¿cómo determinas cuándo dejar de usar el efecto, ya que depende de la image , que es, supongo, parte del useSate gancho, y en ese mismo efecto estás actualizando esa misma image , lo que conducirá a otro uso de efectos (que conduce a un bucle infinito)?

RESPUESTA ACTUALIZADA

Hice un ejemplo similar en codesandbox para verlo por mi cuenta. Me parece que el problema principal aquí es la sincronización entre el CSS aplicado y la actualización real en su componente de reacción. Cuando se usa setInterval con 5000 ms, no significa que se activará justo después de 5000 ms, pero la animación CSS en el otro lado siempre llega a tiempo, por lo que se atasca cuando dos de ellos se desincronizan. Parece que la única forma de resolver esto es recrear elementos img en cada reorden, introduciendo el estado de marca de tiempo y usándolo como parte de cada clave img para forzar la recreación de img en cada actualización. También necesitaría cambiar la animación de una manera más simple.

CSS sería algo como esto:

 @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .image { position: relative; margin: 0 auto; max-width: 1064px; animation: fadeIn 3s; opacity: 1; }

Y el componente funcional sería algo como esto (solo la parte del gancho):

 const [images, setImages] = useState(["1.jpg", "2.jpg", "3.jpg"]); const [dateTimeWhenChanged, setDatetimeWhenChanged] = useState(""); useEffect(() => { const imgs = [...images]; // Time interval same as css animation to fade in const interval = setInterval(() => { // Take the first element and but it to the end imgs.push(...imgs.splice(0, 1)); // Update the state, this seems to desync as time passes setImages(imgs); setDatetimeWhenChanged(new Date().toString()); }, 5 * 1000); return ( <div> {images.map((img, ind) => ( <img key={`${ind}-${dateTimeWhenChanged}`} alt={img} src={`images/${img}`} className="imgg" /> ))} </div> );
about 4 years ago · Juan Pablo Isaza Denunciar

0

Llegué a la conclusión de que tener dos 'relojes' para mantener el tiempo, uno reaccionando setState y el otro css animation, era el núcleo del problema.

Así que ahora mantengo un solo intervalo con un setTimeout para asegurarme de que vaya en orden, luego resto el tiempo que se toma en los tiempos de espera del intervalo y cambio la clase para css

 export const Gallery = styled.div<{ fadeIn: boolean }>` position: relative; margin: 0 auto; max-width: 1064px; transition: opacity 0.3s; opacity: ${({ fadeIn }) => (fadeIn ? 1 : 0)}; `
 import React, { useState, useEffect } from 'react' const [images, setImages] = useState<string[]>([]) const [fadeIn, setFadeIn] = useState<boolean>(true) useEffect(() => { let interval: ReturnType<typeof setInterval> if (images.length) { interval = setInterval(() => { setFadeIn(false) setTimeout(() => { setImages(images => images.slice(1).concat(images[0]) ) setFadeIn(true) }, 400) }, (lapse - 0.4) * 1000) } return () => clearInterval(interval) }, [images]) const getImage = (i: number) => <img src={imgs/${images[i]}`} /> <Gallery fadeIn={fadeIn}> <Portal>{getImage(0)}</Portal> <Thumbnails> <Thumbwrapper>{getImage(1)}</Thumbwrapper> <Thumbwrapper>{getImage(2)}</Thumbwrapper> </Thumbnails> </Gallery>

Sin embargo, usé @Nice Books mejor setState

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