如果我不滚动或单击浏览器,组件内部的 React useState() 数组映射不会更新
React useState() array mapping inside of component doesn't update if I don't scroll or click on browser
我用 React 和 Tailwind 制作了这个效果:
GIF with the effect
如您所见,到目前为止一切顺利。但是,此效果仅在以下情况下有效:
- 我在浏览器上滚动
- 我点击浏览器
- 我打开 Chrome 工具检查器
当我不执行上述操作时会发生这种情况:
GIF with the effect but not working as expected
如您所见,这不是我想要的效果。
所以,显然,这里出现了 React 渲染问题,我被困住了。
在内部,其工作方式如下:
const HomeHeader = () => {
// This are imported images
const IMAGES = [insta, twitter, netflix, mix];
// This is an array that maps inside the component and renders the images as JSX
const [images, setImages] = useState([]);
useEffect(() => {
let counter = 0;
// An interval that creates a new element in the array "images" every 50 miliseconds
const interval = setInterval(() => {
setImages(prevState => [
...prevState,
{
id: counter++,
duration: getRandom(5, 9) * 1000,
image: IMAGES[getRandom(0, IMAGES.length)],
height: getRandom(1, 6),
top: getRandom(0, window.innerHeight - window.innerHeight / 4),
right: getRandom(0, window.innerWidth)
}
]);
}, 50);
return () => clearInterval(interval);
}, [])
// Every time the state variable "images" is changed, add the cool animation to the last image and, when it ends, delete the image from the HTML
useEffect(() => {
if(images.length > 0) {
let image = images[images.length - 1];
let element = document.getElementById(image.id);
element.classList.add('opacity-0');
element.classList.add('scale-125');
setTimeout(() => {
element.parentNode.removeChild(element);
}, image.duration);
}
}, [images])
return (
<div id="header" className="relative h-full bg-gray-900 flex justify-center items-center px-16 overflow-hidden">
<h1 className="bg-black text-gray-200 font-bold text-5xl sm:text-8xl md:text-9xl text-center z-10"></h1>
{
images.map((element, index) => {
return <img key={index} id={element.id} src={element.image} style={{top: element.top, right: element.right}} className={"imageRRSS absolute filter blur-sm w-auto h-" + element.height + "/6 w-auto transform transition-transform-opacity duration-" + element.duration}/>
})
}
</div>
)
}
它的作用是每 50 毫秒向状态数组 images 添加一个新对象,其中包含要添加的图像的属性。
每次添加后,由于是状态变量,React会重新渲染组件内部的映射 return:
{
images.map((element, index) => {
return <img key={index} id={element.id} src={element.image} style={{top: element.top, right: element.right}} className={"imageRRSS absolute filter blur-sm w-auto h-" + element.height + "/6 w-auto transform transition-transform-opacity duration-" + element.duration}/>
})
}
它还会转到 useEffect 并添加很酷的动画,当动画结束时,它会从 HTML:
中删除标签
useEffect(() => {
if(images.length > 0) {
let image = images[images.length - 1];
let element = document.getElementById(image.id);
element.classList.add('opacity-0');
element.classList.add('scale-125');
setTimeout(() => {
element.parentNode.removeChild(element);
}, image.duration);
}
}, [images])
但是,渲染只是在我与浏览器交互时发生。
这就是我对发生的事情的理解。但是,显然有些地方不对劲,因为它没有按预期工作。
有人知道这是怎么回事吗?
谢谢!
好的,解决了。问题在于 React 在元素中立即应用顺风效果。我只是将 onLoad 事件添加到组件中,而不是使用 useEffect,它工作得很好。
我用 React 和 Tailwind 制作了这个效果:
GIF with the effect
如您所见,到目前为止一切顺利。但是,此效果仅在以下情况下有效:
- 我在浏览器上滚动
- 我点击浏览器
- 我打开 Chrome 工具检查器
当我不执行上述操作时会发生这种情况:
GIF with the effect but not working as expected
如您所见,这不是我想要的效果。
所以,显然,这里出现了 React 渲染问题,我被困住了。
在内部,其工作方式如下:
const HomeHeader = () => {
// This are imported images
const IMAGES = [insta, twitter, netflix, mix];
// This is an array that maps inside the component and renders the images as JSX
const [images, setImages] = useState([]);
useEffect(() => {
let counter = 0;
// An interval that creates a new element in the array "images" every 50 miliseconds
const interval = setInterval(() => {
setImages(prevState => [
...prevState,
{
id: counter++,
duration: getRandom(5, 9) * 1000,
image: IMAGES[getRandom(0, IMAGES.length)],
height: getRandom(1, 6),
top: getRandom(0, window.innerHeight - window.innerHeight / 4),
right: getRandom(0, window.innerWidth)
}
]);
}, 50);
return () => clearInterval(interval);
}, [])
// Every time the state variable "images" is changed, add the cool animation to the last image and, when it ends, delete the image from the HTML
useEffect(() => {
if(images.length > 0) {
let image = images[images.length - 1];
let element = document.getElementById(image.id);
element.classList.add('opacity-0');
element.classList.add('scale-125');
setTimeout(() => {
element.parentNode.removeChild(element);
}, image.duration);
}
}, [images])
return (
<div id="header" className="relative h-full bg-gray-900 flex justify-center items-center px-16 overflow-hidden">
<h1 className="bg-black text-gray-200 font-bold text-5xl sm:text-8xl md:text-9xl text-center z-10"></h1>
{
images.map((element, index) => {
return <img key={index} id={element.id} src={element.image} style={{top: element.top, right: element.right}} className={"imageRRSS absolute filter blur-sm w-auto h-" + element.height + "/6 w-auto transform transition-transform-opacity duration-" + element.duration}/>
})
}
</div>
)
}
它的作用是每 50 毫秒向状态数组 images 添加一个新对象,其中包含要添加的图像的属性。
每次添加后,由于是状态变量,React会重新渲染组件内部的映射 return:
{
images.map((element, index) => {
return <img key={index} id={element.id} src={element.image} style={{top: element.top, right: element.right}} className={"imageRRSS absolute filter blur-sm w-auto h-" + element.height + "/6 w-auto transform transition-transform-opacity duration-" + element.duration}/>
})
}
它还会转到 useEffect 并添加很酷的动画,当动画结束时,它会从 HTML:
中删除标签useEffect(() => {
if(images.length > 0) {
let image = images[images.length - 1];
let element = document.getElementById(image.id);
element.classList.add('opacity-0');
element.classList.add('scale-125');
setTimeout(() => {
element.parentNode.removeChild(element);
}, image.duration);
}
}, [images])
但是,渲染只是在我与浏览器交互时发生。
这就是我对发生的事情的理解。但是,显然有些地方不对劲,因为它没有按预期工作。
有人知道这是怎么回事吗?
谢谢!
好的,解决了。问题在于 React 在元素中立即应用顺风效果。我只是将 onLoad 事件添加到组件中,而不是使用 useEffect,它工作得很好。