我目前正在我的应用程序中实现涟漪效应。我使用 Material UI 按钮 (https://material-ui.com/components/buttons/) 作为起点。
在我自己的实现过程中,我遇到了一些我不确定的行为。我已经创建了一个相应的沙箱,其中包含一个基本示例 https://codesandbox.io/s/zealous-cloud-69uvh?file=/src/App.js。
Container
是父组件,Ripple
是子组件。 Container
具有 onMouseUp
和 onMouseDown
处理程序,分别添加和删除子组件。
下面是 onMouseDown
逻辑的一小段摘录。 rippleCounter
变量是一个 ref 对象,它保留一个计数,用于设置 key
的 Ripple
。
setRipples((oldRipples) => {
return [
...oldRipples,
<Ripple
key={rippleCounter.current}
timeout={500}
rippleX={rippleX}
rippleY={rippleY}
rippleSize={rippleSize}
/>
];
});
rippleCounter.current += 1;
};
我了解 useState
是异步的,因此无法保证针对 key
组件设置的 Ripple
会在其递增之前或之后。这是我在理解上遇到一些困难的地方。
示例 2 遵循此异步行为,因为 Ripple
组件在之前或之后设置了其 key
值。由于在某些情况下实现了相同的密钥,这会导致涟漪混乱。
示例 1 似乎没有遵循此行为。 setRipples
函数始终以同步方式运行,rippleCounter
始终在 setRipples
函数运行后递增。即永远不会使用相同的密钥。
示例 1 在移除子组件之前管理和更新状态。
const Ripple = ({
in: inProp,
onExited = () => {},
timeout,
rippleSize,
rippleY,
rippleX
}) => {
const [leaving, setLeaving] = useState(false);
const style = {
width: rippleSize,
height: rippleSize,
top: -(rippleSize / 2) + rippleY,
left: -(rippleSize / 2) + rippleX
};
useLayoutEffect(() => {
if (!inProp) {
setLeaving(true);
const timeoutValue = setTimeout(onExited, timeout);
return () => {
clearTimeout(timeoutValue);
};
}
}, [timeout, inProp, onExited]);
return (
<span style={style} className="ripple">
<span className={"ripple-child" + (leaving ? " leaving" : "")}></span>
</span>
);
};
示例 2 没有被管理的状态。
const Ripple = ({
in: inProp,
onExited = () => {},
timeout,
rippleSize,
rippleY,
rippleX
}) => {
// const [leaving, setLeaving] = useState(false);
const style = {
width: rippleSize,
height: rippleSize,
top: -(rippleSize / 2) + rippleY,
left: -(rippleSize / 2) + rippleX
};
useLayoutEffect(() => {
if (!inProp) {
// setLeaving(true);
const timeoutValue = setTimeout(onExited, timeout);
return () => {
clearTimeout(timeoutValue);
};
}
}, [timeout, inProp, onExited]);
return (
<span style={style} className="ripple">
<span className={"ripple-child" + (!inProp ? " leaving" : "")}></span>
</span>
);
};
为不好的表达道歉。如果我可以提供其他信息,请告诉我。