我试图通过使用React来控制React的新useEffect
“ hook”来控制模态进入和退出DOM的动画。
这是一个有效的代码笔:
https://codepen.io/nicholasstephan/pen/roprgw
和简化版本:
const isOpen = props.isOpen;
const [ animState, setAnimState ] = useState(null);
useEffect(() => {
if(isOpen === true && animState === null) {
setAnimState('entering');
}
if(isOpen === true && animState === 'entering') {
setAnimState('entered');
}
}, [isOpen, animState]);
if(animState === null) {
return null;
}
return (
<div
style={{
opacity: animState === 'entered' ? 1 : 0,
transition: 'opacity 200ms ease-in-out'
}}>
...
</div>
);
我的想法是:
在初始渲染中,animState
是null
,因此我们返回null
。
将isOpen设置为true时,将触发效果并满足第一个条件,并将animState
设置为“ entering”。在这种状态下,组件应返回不透明0
的DOM。
该效果再次触发,并且满足第二个条件,将animState
设置为“ entered”。创建具有1
的不透明度的DOM,并使用CSS过渡进行动画处理。
据我所知,问题在于DOM添加时的不透明度为1,就好像React在批处理多个渲染调用并且仅更新DOM一次一样。如果您看一下代码笔,我正在每个渲染上记录animState
,并且“ closed”状态正在记录,但似乎没有在显示。
会是这种情况吗?在再次运行效果之前,如何确保已发生渲染?
我想知道是否有一种更好的方法来做这样的事情?但是我也很想知道React在这里的幕后行为以及为什么我没有获得入门动画。
答案 0 :(得分:0)
仅仅为不透明度设置动画似乎有点复杂,为什么不将不透明度存储在这样的状态变量中:
const isOpen = props.isOpen;
const [ opacity, setOpacity ] = useState(0);
useEffect(() => {
setOpacity(isOpen ? 1 : 0);
}, [isOpen]);
return (
<div
style={{
opacity,
transition: 'opacity 200ms ease-in-out'
}}>
...
</div>
);
您也可以尝试使用钩子useRef
手动更新不透明度
const isOpen = props.isOpen;
const divEl = useRef(null);
useEffect(() => {
if (divEl) {
divEl.current.style.opacity = 1;
}
}, [divEl]);
if (!isOpen) {
return null;
}
return (
<div
ref={divEl}
style={{
opacity: 0,
transition: 'opacity 200ms ease-in-out'
}}>
...
</div>
);
答案 1 :(得分:0)
我相信React确实在做您期望的事情。是浏览器的行为有些令人惊讶。
在紧接以下情况使用转换时,应当心:
- 使用.appendChild()将元素添加到DOM
- 删除元素的显示:无;财产。
这被视为初始 状态从未发生过,元素始终处于最终状态 州。克服此限制的简单方法是应用 window.setTimeout()几毫秒,然后才更改 您打算过渡到的CSS属性。
如果我更改:
if(status === true && animState === 'closed') {
setAnimState('open');
}
收件人:
if(status === true && animState === 'closed') {
setTimeout(()=>setAnimState('open'), 25);
}
它似乎工作正常。对我来说,如果我使用的超时时间少于8毫秒,它不有效,并且该行为的具体情况可能因浏览器而异。