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

如何获取Gatsby Link跳转目标,为Framer Motion条件渲染不同退出动画

解决方案

1. 重写LocationContext避免全量重渲染

核心逻辑是用useMemo包裹context值,路径变化后自动重置目标路径,从根源避免不必要的更新:

// src/context/locationContext.js
import React, { createContext, useContext, useState, useMemo, useEffect } from "react"
import { useLocation } from "@reach/router" // Gatsby内置路由

const LocationContext = createContext()

export const LocationProvider = ({ children }) => {
  const currentLocation = useLocation()
  const [nextLocation, setNextLocation] = useState(null)

  // 当前路径变化后重置目标路径,避免影响后续转场
  useEffect(() => {
    setNextLocation(null)
  }, [currentLocation.pathname])

  // 缓存context值,仅依赖项变化时才更新
  const contextValue = useMemo(() => ({
    currentLocation,
    nextLocation,
    setNextLocation
  }), [currentLocation, nextLocation])

  return (
    <LocationContext.Provider value={contextValue}>
      {children}
    </LocationContext.Provider>
  )
}

// 封装自定义hooks简化调用
export const useLocationContext = () => useContext(LocationContext)

2. 封装全局自定义Link组件

替代Gatsby原生Link,点击时先记录跳转目标路径再执行跳转:

// src/components/CustomLink.js
import React from "react"
import { Link as GatsbyLink } from "gatsby"
import { useLocationContext } from "../context/locationContext"

const CustomLink = ({ to, children, ...rest }) => {
  const { setNextLocation } = useLocationContext()

  const handleClick = (e) => {
    setNextLocation(to)
    // 执行传入的自定义点击事件
    rest.onClick?.(e)
  }

  return (
    <GatsbyLink to={to} {...rest} onClick={handleClick}>
      {children}
    </GatsbyLink>
  )
}

export default CustomLink

全局替换所有用到Gatsby Link的位置,包括导航栏、项目页底部的下一个项目跳转链接。

3. 项目页条件渲染退出动画

在Project模板组件中根据跳转目标匹配不同的exit变体:

import { motion } from "framer-motion"
import { useLocationContext } from "../context/locationContext"

// 你的变体配置示例
const pageVariants = {
  enter: { opacity: 0 },
  center: { opacity: 1 },
  // 项目间转场的退出动画
  projectExit: { opacity: 0, y: 20, transition: { duration: 0.4 } },
  // 跳转非项目页的退出动画
  globalExit: { opacity: 0, scale: 0.95, transition: { duration: 0.2 } }
}

const Project = ({ pageContext }) => {
  const { nextLocation } = useLocationContext()
  const project = Projects.find(({ id }) => id === pageContext.id)

  // 按照你自己的项目页路径规则修改匹配逻辑
  const isToProjectPage = nextLocation?.startsWith('/works/')
  const activeExitVariant = isToProjectPage ? 'projectExit' : 'globalExit'

  return (
    <Layout>
      {/* 给外层容器绑定motion属性 */}
      <motion.div
        initial="enter"
        animate="center"
        exit={activeExitVariant}
        variants={pageVariants}
      >
        <ProjectWrapper>
          {/* 原有页面内容保持不变 */}
        </ProjectWrapper>
      </motion.div>
    </Layout>
  )
}

额外优化

如果仍存在不必要的重渲染问题,可使用use-context-selector库替代原生useContext,按需订阅nextLocation字段,仅当该字段变化时才触发Project组件重渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 00:36:05