1 year ago

#235233

test-img

JonQuayle

Next JS Issue with data from getInitialProps in _app.js "TypeError: Cannot read properties of undefined"

I'm having an issue displaying data pulled in (from Prismic) with getInitialProps in the _app.js file. I have followed the Prismic slice machine tutorial, which includes defining a header and navigation in Prismic and displaying that data on the frontend - that all works fine.

I've defined a footer now, have included the call for the footer data in the same place and way I have for the header data in the _app.js file, but that data does not display on the frontend. The error message I am seeing is:

TypeError: Cannot read properties of undefined (reading 'data')

and references the call stack to my _document.js file, but I cannot understand where the issue is in that file.

_document.js:

import Document, { Html, Head, Main, NextScript } from 'next/document'
import { repoName } from '../prismicConfiguration'
import Link from 'next/link'

export default class extends Document {

  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx)
    return { ...initialProps }
  }

  render() {
    return (
      <Html lang="en">
                <Head>
                    <script async defer src={`//static.cdn.prismic.io/prismic.js?repo=${repoName}&new=true`} />
                </Head>
        <body className="">
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

_app.js:

import React from 'react'
import NextApp from 'next/app'
import { Client } from '../utils/prismicHelpers'
import '../styles/style.scss'

export default class MyApp extends NextApp {

  static async getInitialProps(appCtx) {
        const menu = await Client().getSingle('menu') || null
        const footer = await Client().getSingle('footer') || null

        console.log("FOOTER", footer)
        console.log("MENU",menu)

    return {
      props: {
        menu: menu,
                footer: footer
      },
    }
  }

  render() {
    const { Component, pageProps, props } = this.props
    return (
      <Component {...pageProps} menu={props.menu} footer={props.footer} />
    )
  }
}

Footer.js (where the data should be getting displayed):

import React from 'react'
import Link from 'next/link'

// Project functions
import { linkResolver } from '../prismicConfiguration'
import { RichText } from 'prismic-reactjs'

// Footer component
export default function Footer({ footer }) {

    return (

        <footer className="footer">
            <div className="container max-width-lg">
                {footer.data.eyebrow}
                <RichText render={footer.data.headline} />
                <RichText render={footer.data.description} />
                <Link href={linkResolver(footer.data.link)}>
                    <a>
                        {footer.data.linkLabel}
                    </a>
                </Link>

                { footer.data.copyrightText }
                { footer.data.signoffText }
            </div>
        </footer>

    )
}

I'm so confused as to why this footer data cannot be displayed or read when it has been defined and called in the same way as the header, which works completely fine. I am console logging both sets of data in the _app.js file and both are returning fine in the terminal, so I am confident what I am adding to the footer component file is correct. For some context, the reason I am pulling this data in the _app.js file is that its data that needs to be across all pages rather than calling it on every single page.

Where am I going wrong here?

Thanks

Addition: The Footer component is being added to a layout component:

import React from 'react'
import { useEffect } from 'react'
import Head from 'next/head'
import { useRouter } from 'next/router'
import Script from 'next/Script'

// Components
import Header from './Header'
import Footer from './Footer'

// Project functions
import * as gtag from '../lib/gtag'

// Layout component
const Layout = ({ children, footer, menu }) => {

    const router = useRouter()

  useEffect(() => {
    const handleRouteChange = (url) => {
      gtag.pageview(url)
    }
    router.events.on('routeChangeComplete', handleRouteChange)
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange)
    }
  }, [router.events])

  return (
    <div className="page_wrapper">

      <Head>
                {/* <meta charSet="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1" />
                <link rel="icon" href="/favicon/favicon.ico" />
                <script dangerouslySetInnerHTML={{ __html: `document.getElementsByTagName("html")[0].className += " js";`}}
                /> */}
                {/* <Link
                    rel="preload"
                    href="/fonts/font-file.woff2"
                    as="font"
                    crossOrigin=""
                /> */}
      </Head>

            <Script
                id="codyhouse-utils-js"
                src="https://unpkg.com/codyhouse-framework/main/assets/js/util.js"
                strategy="beforeInteractive"
            />

            <Script
                strategy="afterInteractive"
                src={`https://www.googletagmanager.com/gtag/js?id=${gtag.GA_TRACKING_ID}`}
            />

            <Script
                id="gtag-init"
                strategy="afterInteractive"
                dangerouslySetInnerHTML={{
                    __html: `
                        window.dataLayer = window.dataLayer || [];
                        function gtag(){dataLayer.push(arguments);}
                        gtag('js', new Date());
                        gtag('config', '${gtag.GA_TRACKING_ID}', {
                            page_path: window.location.pathname,
                        });
                    `,
                }}
            />

            {/* <Script
                src="https://www.google.com/recaptcha/api.js?&render=explicit"
                strategy="afterInteractive"
            /> */}

      <Header menu={menu} />

      <main>

                {children}

            </main>

            <Footer footer={footer} />

    </div>
  );
};

export default Layout

javascript

html

reactjs

next.js

prismic.io

0 Answers

Your Answer

Accepted video resources