Reactjs 允许组件检测盖茨比中的路线变化

Reactjs 允许组件检测盖茨比中的路线变化,reactjs,gatsby,Reactjs,Gatsby,在盖茨比项目中,我有一个标题组件,它在每个页面上都是持久的。标题具有显示导航的模式。每当路线改变时,我需要将等参状态设置为false,以便导航模式关闭。由于路线不仅可以通过单击模式中的链接来更改,还可以通过使用浏览器上的“后退”按钮来更改,因此我不希望使用链接上的事件来关闭模式 在Gatsby中,我可以使用Gatsby-browser.js中的onRouteUpdate来检测路由更改,这非常有效。但我需要将事件传递给我的组件,这就是我遇到的困难。我简化了下面的代码以显示设置 gatsby-bro

在盖茨比项目中,我有一个标题组件,它在每个页面上都是持久的。标题具有显示导航的模式。每当路线改变时,我需要将等参状态设置为false,以便导航模式关闭。由于路线不仅可以通过单击模式中的链接来更改,还可以通过使用浏览器上的“后退”按钮来更改,因此我不希望使用链接上的事件来关闭模式

在Gatsby中,我可以使用Gatsby-browser.js中的onRouteUpdate来检测路由更改,这非常有效。但我需要将事件传递给我的组件,这就是我遇到的困难。我简化了下面的代码以显示设置

gatsby-browser.js:

import React from "react"
import Layout from "./src/components/layout"

export const wrapPageElement = ({ element, props }) => {
  return <Layout {...props}>{element}</Layout>
}

export const onRouteUpdate = () => {
  console.log("onRouteUpdate") // this works
}
从“React”导入React
从“/src/components/Layout”导入布局
export const wrapPageElement=({element,props})=>{
返回{element}
}
导出const onRouteUpdate=()=>{
console.log(“onRouteUpdate”)//这很有效
}
layout.js:

import React from "react"

import Header from "./header"
import Footer from "./footer"

const Layout = ({ children }) => (
    <>
      <Header />
      <main>
        {children}
      </main>
      <Footer />
    </>
  )

export default Layout
从“React”导入React
从“/Header”导入标题
从“/Footer”导入页脚
常量布局=({children})=>(
{儿童}
)
导出默认布局
header.js:

import React, { useState } from "react"

const Header = () => {
  const [isOpen, setIsOpen] = useState(null)
  const toggleState = ({ props }) => {
    let status
    if (props) status = props.status
    else status = !isOpen
    setIsOpen(status)
  }
  return (
    <header>
      <div>This is the header</div>
      <button onClick={toggleState}>Toggle Open/Close</button>
      <button onClick={toggleState({ status: false })}>This will always close</button>
      /* logic here uses isOpen state to determine display */
    </header>
  )
}

export default Header
import React,{useState}来自“React”
常量头=()=>{
常量[isOpen,setIsOpen]=useState(null)
const-toggleState=({props})=>{
让状态
如果(道具)状态=道具状态
其他状态=!isOpen
塞西彭(状态)
}
返回(
这是标题
切换打开/关闭
这将永远关闭
/*这里的逻辑使用等参状态来确定显示*/
)
}
导出默认标题

我为自己的问题想出了一个解决方案,所以我想与大家分享。欢迎提出任何意见/改进

首先,我们不需要在gatsby-broser.js中使用“onRouteUpdate”,所以让我们删除它:

/* gatsby-browser.js */
import React from "react"
import Layout from "./src/components/layout"

export const wrapPageElement = ({ element, props }) => {
  return <Layout {...props}>{element}</Layout>
}
/*gatsby-browser.js*/
从“React”导入React
从“/src/components/Layout”导入布局
export const wrapPageElement=({element,props})=>{
返回{element}
}
然后,在layout.js中,确保将位置传递给标题:

/* layout.js */
import React from "react"

import Header from "./header"
import Footer from "./footer"

const Layout = ({ children, location }) => (
    <>
      <Header location={location} />
      <main>
        {children}
      </main>
      <Footer />
    </>
  )

export default Layout
/*layout.js*/
从“React”导入React
从“/Header”导入标题
从“/Footer”导入页脚
常量布局=({子项,位置})=>(
{儿童}
)
导出默认布局
最后,在header.js中,位置通过使用useRef钩子存储在对header元素的引用上。useEffect钩子将在路由更改时触发,因此我们可以使用它来比较:

/* header.js */
import React, { useState, useEffect, useRef } from "react"

const Header = () => {
  const [isOpen, setIsOpen] = useState(null)
  const myRef = useRef({
    location: null,
  })
  useEffect(() => {
    // set the location on initial load
    if (!myRef.current.location) myRef.current.location = location
    // then make sure dialog is closed on route change
    else if (myRef.current.location !== location) {
      if (isOpen) toggleState({ status: false })
      myRef.current.location = location
    }
  })
  const toggleState = ({ props }) => {
    let status
    if (props) status = props.status
    else status = !isOpen
    setIsOpen(status)
  }
  return (
    <header ref={myRef}>
      <div>This is the header</div>
      <button onClick={toggleState}>Toggle Open/Close</button>
      <button onClick={toggleState({ status: false })}>This will always close</button>
    </header>
  )
}

export default Header
/*header.js*/
从“React”导入React,{useState,useffect,useRef}
常量头=()=>{
常量[isOpen,setIsOpen]=useState(null)
常量myRef=useRef({
位置:空,
})
useffect(()=>{
//在初始载荷下设置位置
如果(!myRef.current.location)myRef.current.location=位置
//然后确保对话框在路线更改时关闭
else if(myRef.current.location!==位置){
if(isOpen)toggleState({status:false})
myRef.current.location=位置
}
})
const-toggleState=({props})=>{
让状态
如果(道具)状态=道具状态
其他状态=!isOpen
塞西彭(状态)
}
返回(
这是标题
切换打开/关闭
这将永远关闭
)
}
导出默认标题

希望这能帮助任何寻找类似功能的人。

我解决这一问题的首选方法是使用盖茨比使用的未记录的
globalHistory

从'@reach/router'导入{globalHistory}
useffect(()=>{
返回globalHistory.listen({action})=>{
if(action=='PUSH')setIsOpen(false)
})
},[setIsOpen])
现在,无论何时切换路线,都会触发上述效果


.

谢谢!工作很有魅力。我找到的最简单的方法!!