You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AnimatePresence失效:React登录注册组件循环切换动画异常

解决Framer Motion退出动画不生效的问题

问题原因

AnimatePresence生效的两个核心条件未满足:

  1. AnimatePresence的直接子元素必须带有唯一且稳定的key:你当前把key放在子组件内部的motion元素上,AnimatePresence无法追踪组件的卸载状态,导致直接移除DOM。
  2. 子组件根元素的min-h-screen样式和父容器的w-[40vw]冲突,布局异常会干扰动画过渡效果。

解决方案

1. 给AnimatePresence的直接子元素添加唯一key

修改UserLoginSignUp.jsx,在条件渲染的<Login>和<Signup>组件上添加key,同时给父容器补充高度属性确保布局稳定:

import { Login } from "./Login";
import { Signup } from "./Signup";
import { AnimatePresence } from "framer-motion";

function UserLoginSignUp({ isloged, setisloged }) {
  return (
    <>
      <div>
        <div className="w-[40vw] h-screen">
          <AnimatePresence>
            {isloged ? (
              <Login key="login" setisloged={setisloged} />
            ) : (
              <Signup key="signup" setisloged={setisloged} />
            )}
          </AnimatePresence>
        </div>
        <div></div>
      </div>
    </>
  );
}

export { UserLoginSignUp };

2. 调整子组件的全屏样式,避免布局冲突

修改Login.jsx和Signup.jsx的根motion.div,将min-h-screen改为h-full,让子组件高度适配父容器:

Login.jsx 修改后

import { useState } from "react";
import { motion } from "framer-motion";

function Login({ setisloged }) {
  const [masterKey, setMasterKey] = useState("");

  const handleLogin = () => {
  };

  const signupHandler = () => {
    setisloged(false);
  };

  return (
    <motion.div
      initial={{ opacity: 0, y: -100 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 1 }}
      exit={{ opacity: 0, y: 200 }}
      className="h-full flex items-center justify-center bg-gradient-to-b from-[#95dab6] to-[#83b2d0]"
    >
      <motion.div
        initial={{ opacity: 0, y: -100 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ duration: 1 }}
        exit={{ opacity: 0, y: 200 }}
        className="bg-white p-8 rounded shadow-md w-96"
      >
        <h2 className="text-2xl font-semibold mb-4">Login</h2>
        <div className="mb-4">
          <input
            type="text"
            placeholder="Enter master key"
            className="w-full px-3 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-red-600  focus:border-blue-300"
            value={masterKey}
            onChange={(e) => setMasterKey(e.target.value)}
          />
        </div>
        <button
          className="w-full bg-[#95dab6] text-white py-2 rounded hover:bg-green-400"
          onClick={handleLogin}
        >
          Login
        </button>
        <p className="mt-4 text-center">
          Don't have an account?{" "}
          <span
            className="text-green-400 cursor-pointer"
            onClick={signupHandler}
          >
            Signup
          </span>
        </p>
      </motion.div>
    </motion.div>
  );
}

export { Login };

Signup.jsx 修改后

import { useState } from "react";
import { motion } from "framer-motion";

function Signup({ setisloged }) {
  const [fullName, setFullName] = useState("");
  const [email, setEmail] = useState("");
  const [masterKey, setMasterKey] = useState("");

  const handleSignup = () => {
  };

  const loginHandler = () => {
    setisloged(true);
  };

  return (
    <motion.div
      initial={{ opacity: 0, y: -100 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 1 }}
      exit={{ opacity: 0, y: 200 }}
      className="h-full flex items-center justify-center bg-gradient-to-b from-blue-600 to-purple-400"
    >
      <motion.div
        initial={{ opacity: 0, y: -100 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ duration: 1 }}
        exit={{ opacity: 0, y: 200 }}
        className="bg-white p-8 rounded shadow-md w-96"
      >
        <h2 className="text-2xl font-semibold mb-4">Signup</h2>
        <div className="mb-4">
          <input
            type="text"
            placeholder="Enter Full Name"
            className="w-full px-3 py-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
            value={fullName}
            onChange={(e) => setFullName(e.target.value)}
          />
        </div>
        <div className="mb-4">
          <input
            type="email"
            placeholder="Enter Email"
            className="w-full px-3 py-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
        </div>
        <div className="mb-4">
          <input
            type="text"
            placeholder="Enter your Masterkey"
            className="w-full px-3 py-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
            value={masterKey}
            onChange={(e) => setMasterKey(e.target.value)}
          />
        </div>
        <button
          className="w-full bg-blue-500 text-white py-2 rounded hover:bg-blue-600 mb-2"
          onClick={handleSignup}
        >
          Signup
        </button>
        <button
          className="w-full bg-gray-300 text-gray-700 py-2 rounded hover:bg-gray-400"
          onClick={loginHandler}
        >
          Login
        </button>
      </motion.div>
    </motion.div>
  );
}

export { Signup };

原理说明

  • AnimatePresence通过key识别元素的挂载/卸载状态,只有直接子元素的key才能被正确追踪,内部元素的key无法触发退出动画。
  • 调整子组件高度为h-full后,父容器的尺寸限制生效,避免全屏布局导致的动画过渡时的视觉异常。

内容的提问来源于stack exchange,提问作者Krishna Biswal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 03:25:05