Framer Motion & React Portals:没有转换发生
Framer Motion & React Portals : No Transitions Occur
我正在向现有网站添加一些 React 模块。为此,我通过 React Portals 安装我的 React 组件。
简而言之,虽然我的组件确实按预期安装,但未触发动画。例如,他们仍然坚持 opacity
的 0
。我希望这些组件在安装时从 opacity
0
过渡到 1
,然后根据 initial
在退出时从 0
过渡到 1
animate
和 exit
<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
组件中使用动画,你需要导入一个额外的“功能包”,如 domAnimation
或 domMax
.
更多信息在这里:
Framer.com: Reduce bundle size
我正在向现有网站添加一些 React 模块。为此,我通过 React Portals 安装我的 React 组件。
简而言之,虽然我的组件确实按预期安装,但未触发动画。例如,他们仍然坚持 opacity
的 0
。我希望这些组件在安装时从 opacity
0
过渡到 1
,然后根据 initial
在退出时从 0
过渡到 1
animate
和 exit
<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
组件中使用动画,你需要导入一个额外的“功能包”,如 domAnimation
或 domMax
.
更多信息在这里: Framer.com: Reduce bundle size