Framer Motion & React Portals:没有转换发生

Framer Motion & React Portals : No Transitions Occur

我正在向现有网站添加一些 React 模块。为此,我通过 React Portals 安装我的 React 组件。

简而言之,虽然我的组件确实按预期安装,但未触发动画。例如,他们仍然坚持 opacity0。我希望这些组件在安装时从 opacity 0 过渡到 1,然后根据 initial 在退出时从 0 过渡到 1 animateexit <AnimatePresence> 内的每个 child 道具。

可以在 CodeSandbox here.

上找到显示错误的人为但有效的示例

CodeSandbox 中的代码也如下所示:

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
   ...
  </head>

  <body>
    <div id="react-root"></div>
    <h1>Static Content</h1>
    <button id="start-portal">Show Modal</button>
    <div id="portal"></div>
  </body>
</html>

Context.js

import React from "react";

const INITIAL_STATE = {
  activeItem: -1
};

const Context = React.createContext(null);

const ContextProvider = ({ children }) => {
  const [store, setStore] = React.useState(INITIAL_STATE);

  React.useEffect(() => {
    const startEl = document.getElementById("start-portal");
    startEl.addEventListener("click", () => setActiveItem(0));
    return () => {
      startEl.removeEventListener("click", () => setActiveItem(0));
    };
  }, []);

  const setActiveItem = (activeItem) => {
    console.log("SETTING ACTIVE ITEM TO " + activeItem);
    setStore((prevState) => {
      return {
        ...prevState,
        activeItem
      };
    });
  };

  return (
    <Context.Provider
      value={{
        ...store,
        setActiveItem
      }}
    >
      {children}
    </Context.Provider>
  );
};

function useContext() {
  return React.useContext(Context);
}

export { ContextProvider, useContext };

index.js

import React from "react";
import ReactDOM from "react-dom";

import Modal from "./Modal";

import { ContextProvider } from "./Context";

import "./styles.css";

const REACT_ROOT = document.getElementById("react-root");
const PORTAL_ROOT = document.getElementById("portal");

const PortalModal = () => {
  if (!PORTAL_ROOT) return null;
  return ReactDOM.createPortal(<Modal />, PORTAL_ROOT);
};

const App = () => (
  <ContextProvider>
    <PortalModal />
  </ContextProvider>
);

ReactDOM.render(<App />, REACT_ROOT);

Modal.js

import React from "react";
import { AnimatePresence, m } from "framer-motion";

import { useContext } from "./Context";

const Modal = () => {
  const { activeItem, setActiveItem } = useContext();

  return (
    <AnimatePresence exitBeforeEnter>
      {activeItem === 0 && (
        <m.div
          key={"step-1"}
          className={"step"}
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
        >
          <h2>STEP 1</h2>
          <button onClick={() => setActiveItem(-1)}>CLOSE</button>
          <button onClick={() => setActiveItem(1)}>NEXT</button>
        </m.div>
      )}
      {activeItem === 1 && (
        <m.div
          key={"step-2"}
          className={"step"}
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
        >
          <h2>STEP 2</h2>
          <button onClick={() => setActiveItem(-1)}>CLOSE</button>
          <button onClick={() => setActiveItem(0)}>PREV</button>
        </m.div>
      )}
    </AnimatePresence>
  );
};

export default Modal;

您可以从 m 切换到 motion(在导入和组件中),一切都按预期工作。

m 不是 motion 的 1:1 别名,它是精简版。 如果你想在 m 组件中使用动画,你需要导入一个额外的“功能包”,如 domAnimationdomMax.

更多信息在这里: Framer.com: Reduce bundle size