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

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

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 Report

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 Report

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 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!