使用 React Router 和 React Hooks 绕过非路由组件中的更新阻止程序

Bypassing update blocker in non-route component with React Router and React Hooks

我将 React Router 与通用页面组件一起使用,该组件基于 slug 从 WP Rest API 获取内容。我可以直接通过 url 访问页面,并且路由有效。

我的 Footer 组件中有一个小菜单,它使用 React Router <Link> 组件链接到使用 Page 组件的各个页面。

当我单击这些链接时,url 正在更新,但页面组件没有使用更新后的 slug 重新呈现,因此没有抓取正确的页面内容。

这绝对是更新阻塞,如 React Router 文档中所述:https://reacttraining.com/react-router/web/guides/dealing-with-update-blocking

这涵盖了大多数解决方案,但在我的例子中,Footer 组件不是 Route,而是 Layout 组件的子组件,Layout 组件也是无路由的,并包装了所有其他组件。

要修复,文档建议我需要将 React Router location prop 发送到组件树下。

我已经尝试使用 withRouter 导出所有组件到组件树下,应该传递这个属性,但它不起作用。

如何在单击 <Footer> 组件中的 <Link> 时让 <Page> 组件更新?

App.js中的路线:

<BrowserRouter>
    <Layout
        addToCart={addToCart}
        removeFromCart={removeFromCart}
        clearCart={clearCart}
        cart={cart}
        catalog={catalog}
    >
        <Switch>
            <Route exact path="/" render={() => <Home catalog={catalog} />} />
            <Route
                exact
                path="/catalog"
                render={() => (
                    <Catalog addToCart={addToCart} catalog={catalog} />
                )}
            />
            <Route path="/:slug" render={props => <Page {...props} />} />
            <Route
                path="/catalog/:category/:slug"
                render={() => (
                    <SingleProduct addToCart={addToCart} catalog={catalog} />
                )}
            />
        </Switch>
    </Layout>
</BrowserRouter>

Layout.js(简体):

<Layout>
    <Header />
    {children}
    <Footer />
<Layout

<Footer /> 中的链接:

<ul className="nostyle footer-links">
    <li>
        <Link to="/faq">FAQ</Link>
    </li>
    <li>
        <Link to="/about">About</Link>
    </li>
    <li>
        <Link to="/contact">Contact Us</Link>
    </li>
</ul>
//...
export default withRouter(Footer)

Page.js:

const Page = props => {
    const slug = props.match.params.slug
    const [page, setPage] = useState()

    const fetchPage = async () => {
        const result = await axios(
            `${params.liveUrl}${params.pages}?slug=${slug}`
        )
        setPage(result.data)
    }

    useEffect(() => {
        fetchPage()
    }, [])

    return (
        <Fragment>
            <div className="page" key={page[0].slug}>
                {page[0].content}
            </div>
        </Fragment>
    )
}

export default withRouter(Page)

因此,如果我直接访问 /faq/about,它会按照路由中的指示加载 <Page /> 组件,传入 slug 并正确显示所有内容。

但是,如果我单击 <Footer /> 中的一个链接,url 会发生变化,但 <Page /> 组件不会刷新为新的 slug,因此不会刷新正确的页面数据。如果我重新加载页面,则会加载正确的数据。

如何在更改路由时强制 <Page> 组件更新?

请注意,我使用的是 React hooks 而不是 Redux。

谢谢!

您需要为页面组件设置唯一键,这样每次键更改时都会呈现该组件的新实例。

假设您的 slug 是独一无二的,您可以执行以下操作:

<Page key={props.match.params.slug} {...props} />

或者,您也可以这样做:

<Page key={window.location.pathname} {...props} />