【发布时间】:2020-12-06 02:50:30
【问题描述】:
我正在尝试在 React 中构建一个准系统 css 转换包装器,其中一个布尔属性控制一个 HTML 类,用于切换设置为转换的 css 属性。对于有问题的用例,我们还希望在入口转换之前和退出转换之后卸载组件 (return null)。
为此,我使用了两个布尔状态变量:一个控制安装,另一个控制 HTML 类。当props.in 从false 变为true 时,我将mounted 设置为true。现在的诀窍是:如果类在第一次渲染时立即设置为"in",则不会发生转换。我们需要先用 "out" 类渲染组件,然后将类更改为 "in"。
setTimeout 可以工作,但非常随意,并不严格与 React 生命周期相关联。我发现即使是 10 毫秒的超时有时也无法产生效果。这是一个废话。
我曾认为使用useEffect 和mounted 作为依赖项会起作用,因为组件将被渲染并且效果会发生在:
useEffect(if (mounted) { () => setClass("in"); }, [mounted]);
(请参阅下面上下文中的完整代码)
但这无法产生过渡。我相信这是因为 React 会批处理操作并选择何时渲染到真实的 DOM,并且大多数时候直到效果也发生之后才会这样做。
我如何保证我的类值仅在 mounted 设置为 true 之后呈现组件之后才发生更改?
简化的 React 组件:
function Transition(props) {
const [inStyle, setInStyle] = useState(props.in);
const [mounted, setMounted] = useState(props.in);
function transitionAfterMount() {
// // This can work if React happens to render after mounted get set but before
// // the effect; but this is inconsistent. How to wait until after render?
setInStyle(true);
// // this works, but is arbitrary, pits UI delay against robustness, and is not
// // tied to the React lifecycle
// setTimeout(() => setInStyle(true), 35);
}
function unmountAfterTransition() {
setTimeout(() => setMounted(false), props.duration);
}
// mount on props.in, or start exit transition on !props.in
useEffect(() => {
props.in ? setMounted(true) : setInStyle(false);
}, [props.in]);
// initiate transition after mount
useEffect(() => {
if (mounted) { transitionAfterMount(); }
}, [mounted]);
// unmount after transition
useEffect(() => {
if (!props.in) { unmountAfterTransition(); }
}, [props.in]);
if (!mounted) { return false; }
return (
<div className={"transition " + inStyle ? "in" : "out"}>
{props.children}
</div>
)
}
示例样式:
.in: {
opacity: 1;
}
.out: {
opacity: 0;
}
.transition {
transition-property: opacity;
transition-duration: 1s;
}
及用法
function Main() {
const [show, setShow] = useState(false);
return (
<>
<div onClick={() => setShow(!show)}>Toggle</div>
<Transition in={show} duration={1000}>
Hello, world.
</Transition>
<div>This helps us see when the above component is unmounted</div>
</>
);
}
【问题讨论】:
标签: reactjs react-hooks css-transitions