【问题标题】:NEXT JS - How to prevent layout get re-mounted?NEXT JS - 如何防止重新安装布局?
【发布时间】:2020-04-18 12:26:06
【问题描述】:

接下来尝试布局模式:

https://github.com/zeit/next.js/tree/canary/examples/layout-component

问题是布局组件会在每次页面更改时重新安装。我需要将布局组件用作容器,以便在每次挂载时从服务器获取数据。如何防止重新安装布局?还是我错过了什么?

【问题讨论】:

    标签: reactjs next.js


    【解决方案1】:

    另外,请确保将所有<a href=""></a> 替换为<Link href=""></Link>,注意只有将Html 标记更改为链接。

    我为此苦苦挣扎了很多天,虽然我做的一切都是正确的,但这些 <a> 标签是导致 _app.js 在页面更改时重新挂载的罪魁祸首

    【讨论】:

      【解决方案2】:

      尽管这是主题Layout 一次又一次地挂载,但此问题的根本原因是您在某些子组件中加载了一些数据,这些数据被一次又一次地获取。

      经过一番折腾,我发现这些问题实际上都不是 Next.Js 或 SWR 解决的问题。回到第一个问题,问题是如何将单个数据副本简化到某个子组件。

      上下文

      context 为例。

      Config.js

      import { createContext } from 'react'
      export default createContext({})
      

      _App.js

      import Config from '../Config'
      
      export default function App({ Component, pageProps }) {
        return (
          <Config.Provider value={{ user: { name: 'John' }}}>
            <Component {...pageProps} />
          </Config.Provider>
        )
      }
      

      头像.js

      import { useContext } from 'react'
      import Config from '../Config'
      
      function Avatar() {
        const { user } = useContext(Config)
        return (
          <span>
            {user.name}
          </span>
        )
      }
      
      export default Avatar
      

      无论您如何装载和卸载,只要_app 没有,您最终都不会重新渲染。

      可写

      上面的例子只是处理可读的。如果它是可写的,您可以尝试将状态传递到上下文中。 setUser 将负责消费者中的设置。

        <Provider value={useState({})} />
      
        const [user, setUser] = useContext(Config)
      

      setUser 已“缓存”,不会被更新。所以我们可以使用这个函数在子消费者中随时重置用户。


      还有其他方法,例如。反应反冲。但或多或少您正在处理一个状态管理系统,以将副本(值或函数)发送到其他地方而不触及其他节点。我会留下这个作为答案,因为即使我们解决了布局问题,这个问题也不会消失。而如果我们解决了这个问题,我们就根本不需要处理 Layout 了。

      【讨论】:

        【解决方案3】:

        如果您将 Layout 组件放在页面组件中,它将重新安装在页面导航(页面切换)上。

        您可以用_app.js 中的Layout 组件包装您的页面组件,它应该会阻止它重新安装。

        类似这样的:

        // _app.js
        import Layout from '../components/Layout';
        
        class MyApp extends App {
         static async getInitialProps(appContext) {
            const appProps = await App.getInitialProps(appContext);
            return {
              ...appProps,
            };
          }
        
          render() {
            const { Component, pageProps } = this.props;
        
            return (
              <Layout>
                <Component {...pageProps} />
              <Layout />
            );
          }
        }
        
        export default MyApp;
        

        【讨论】:

        • 如果我需要在布局组件中的 ComponentDidMount 上从服务器获取数据怎么办?像容器一样使用它。我的项目中还需要多个容器。 Next 可以吗?
        • 您可以在其中存储“全局”数据,并(通过上下文)公开页面组件的 api
        • 所以布局重新渲染是必要的邪恶?对此无能为力吗?
        • 如果它在页面内,并且您正在导航出去 -> 必须安装新页面,因此您的布局将被重新安装。
        • 有一种方法,通过使用“某物”(上下文)将状态保持在_app,并且您的布局将使用此上下文 api 来获取(或使用缓存数据)
        【解决方案4】:

        这对我的持久布局很有帮助。作者组合了一个函数,将您的页面组件包装在您的 Layout 组件中,然后将该 fetch 函数传递给您的 _app.js。这样 _app.js 实际上是呈现布局的组件,但您可以指定哪些页面使用哪个布局(如果您有多个布局)。

        因此,您可以灵活地在整个网站中使用多个布局,但那些共享相同布局的页面实际上将共享相同的布局组件,并且不必在导航中重新安装。

        这里是完整文章的链接 Persistent Layout Patterns in Next.js

        这里是重要的代码sn-ps。一个页面,然后是 _app.js

        // /pages/account-settings/basic-information.js
        import SiteLayout from '../../components/SiteLayout'
        import AccountSettingsLayout from '../../components/AccountSettingsLayout'
        
        const AccountSettingsBasicInformation = () => (
          <div>{/* ... */}</div>
        )
        
        AccountSettingsBasicInformation.getLayout = page => (
          <SiteLayout>
            <AccountSettingsLayout>{page}</AccountSettingsLayout>
          </SiteLayout>
        )
        
        export default AccountSettingsBasicInformation
        
        // /pages/_app.js
        import React from 'react'
        import App from 'next/app'
        
        class MyApp extends App {
          render() {
            const { Component, pageProps, router } = this.props
        
            const getLayout = Component.getLayout || (page => page)
        
            return getLayout(<Component {...pageProps}></Component>)
          }
        }
        
        export default MyApp
        

        【讨论】:

        • 很好的答案,非常聪明!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-16
        • 1970-01-01
        相关资源
        最近更新 更多