在 Gatsby 项目中,我有一个标题组件,它在每个页面上都是持久的。标题有一个模式来显示导航。每当路线更改时,我都需要将 isOpen 状态设置为 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
}
Run Code Online (Sandbox Code Playgroud)
布局.js:
import React from "react"
import Header from "./header"
import Footer from "./footer"
const Layout = ({ children }) => (
<>
<Header />
<main>
{children}
</main>
<Footer />
</>
)
export default Layout
Run Code Online (Sandbox Code Playgroud)
头文件.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
Run Code Online (Sandbox Code Playgroud)
小智 14
我解决这个问题的首选方法是使用Gatsby使用的未记录的globalHistoryfrom @reach/router。
import { globalHistory } from '@reach/router'
useEffect(() => {
return globalHistory.listen(({ action }) => {
if (action === 'PUSH') setIsOpen(false)
})
}, [setIsOpen])
Run Code Online (Sandbox Code Playgroud)
现在每当您切换路线时,上述效果都会触发。
来源。
我想出了一个解决我自己问题的方法,所以我想我会分享。任何意见/改进总是受欢迎的。
首先,我们不需要在 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>
}
Run Code Online (Sandbox Code Playgroud)
然后,在 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
Run Code Online (Sandbox Code Playgroud)
最后,在 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
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助任何寻找类似功能的人。
| 归档时间: |
|
| 查看次数: |
3157 次 |
| 最近记录: |