No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Curso de Next.js

Curso de Next.js

Jonathan Alvarez

Jonathan Alvarez

Extendiendo el App

13/27
Recursos

Aportes 25

Preguntas 5

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

En el archivo _app podemos inyectarle an谩bolicos (providers, themes, props, o cualquier cosa que necesitemos) a toda nuestra aplicaci贸n.

Todos los cambios en _app y _document, requieren reinicio de servidor.

En react 18 children fue eliminado del tipo FC, para que typescript no de error debes de a帽adirlo por cuenta propia

import React from 'react'
import { Navbar } from '@components/Navbar/Navbar'

type Props = {
  children: React.ReactNode;
};

export const Layout: React.FC<Props> = ({ children }) => {
  return (
    <>
      <Navbar />
      {children}
      <footer>
        <p>This is a footer</p>
      </footer>
    </>
  )
}

Soluci贸n de Stack Overflow

Documentaci贸n de Custom App:
https://nextjs.org/docs/advanced-features/custom-app

Casos de uso:

  • Providers (Context)
  • Themes
  • Layout
  • Props adicionales

Y Que pasa si queremos tener dos layouts ejemplo la pagina login esa no tiene ni navbar ni footer como hacemos para tener dos o tres layouts 驴?

Esto hice para mostrar la p谩gina 404 sin el lay out.

import React from 'react';
import { useRouter } from 'next/router';
import Layout from '../src/components/Layout';
import AppContext from '../src/context/AppContext';
import useInitialState from '../src/hooks/useInitialState'

function MyApp({ Component, pageProps }) {
  const router = useRouter();
  const initialState = useInitialState();
  return <AppContext.Provider value={initialState}><CustomLayout pathname={router.pathname}><Component {...pageProps} /></CustomLayout></AppContext.Provider>
}

const CustomLayout = ({ pathname, children }) => (
  <>
    {
      pathname === "/_error" ? <>{children}</>
        : (
          <Layout>{children}</Layout>
        )
    }
  </>
)
// Only uncomment this method if you have blocking data requirements for
// every single page in your application. This disables the ability to
// perform automatic static optimization, causing every page in your app to
// be server-side rendered.
//
// MyApp.getInitialProps = async (appContext) => {
//   // calls page's `getInitialProps` and fills `appProps.pageProps`
//   const appProps = await App.getInitialProps(appContext);
//
//   return { ...appProps }
// }

export default MyApp

馃専 Extendiendo el app de Next.js

<h4>Ideas/conceptos claves</h4>

documentaci贸n de Next.js para un custom app

Advanced Features: Custom App | Next.js

<h4>Apuntes</h4>

La forma en la que Next.js renderiza en el navegador los contenidos es en el siguiente orden:

  • Document
    • App
      • Nuestra Aplicaci贸n

para usar el app de nuestra aplicaci贸n lo que haremos sera utilizar el template de la documentaci贸n de Next.js para un custom app, el cual debemos crear un archivo llamado 鈥淿app.js鈥 en pages

import { AppProps } from 'next/app'

function MyApp({ Component, pageProps }: AppProps) {
  // Providers - Context/Providers, Theme, data
  // Layout
  // props adicionales
  return <Component {...pageProps} />
}

export default MyApp

RESUMEN: Para crear contenedores de nuestra aplicaciones, que deseemos aplicarlo a nivel global, es muy util usar el app de Next.js creando el archivo _app.js

Una opcion alternativa para los nombramientos de los componentes es ponerle el nombre a la carpeta y al archivo tsx llamarlo index . Es decir :

Layout >
index.tsx

Esto con el fin de que en el import se haga referencia a una ruta mas corta e igual de diciente que la que coloca Jonathan, asi:

import Layout from '../components/Layout
	
en vez de 

import Layout from '../components/Layout/Layout';

Extendiendo el App

NextJS primero renderiza el document, luego el app y ese app es el que engloba nuestra aplicaci贸n.

Cuando hacemos cambios en app o en document debemos reiniciar el servidor.

Creamos un componente Layout:

import React from 'react'
import Navbar from 'components/Navbar/Navbar'

const Layout: React.FC = ({ children }) => {
  return (
    <div>
      <Navbar />
      {children}
      <footer>This is the footer</footer>
    </div>
  )
}

export default Layout

Y lo usamos en 鈥榩ages/_app.tsx鈥:

import type { AppProps } from 'next/app'
import Layout from '../components/Layout/Layout'

export default function MyApp({ Component, pageProps }: AppProps): JSX.Element {
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  )
}

Segun la documentacion para typescript de custom app en nextjs
en este momento, inicialmente el archivo app.tsx viene quedando

import type { AppProps } from 'next/app'

export default function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

A mi bo me funciono el React.FC, en este articulo explican porque no es buena pr谩ctica (Le铆 por ah铆 que su uso fue descontinuado) y que podemos usar en su lugar.

Cuando hacemos una aplicaci贸n con React, el archivo que contiene toda nuestra aplicaci贸n es el App.js, sin embargo, con NextJS no hace falta que lo creemos porque este ya viene por debajo con el. Pero qu茅 pasa si queremos extender o cambiar la funcionalidad que viene por defecto?

Bueno en ese caso como vimos la extensi贸n del document, tambi茅n podemos extender lo que viene por defecto en el App.
Para eso, como lo hicimos con document creando el archivo document_.tsx || _document.jsx, debemos crear un archivo debajo de pages llamado _pages.jsx o .tsx.

Por qu茅 es 煤til extender el app por defecto de next?

  • Podemos crear Providers (Context, Redux)
  • Crear el provider del theme de la aplicaci贸n
  • Pasar datos desde un archivo a cualquier otro
  • Crear layouts para toda nuestra aplicaci贸n
  • Pasar props adicionales

En el archivo _app que vamos a crear, debemos utilizar un template que la documentaci贸n oficial de NextJS nos proporciona

    import { AppProps } from 'next/app'
    function MyApp({ Component, pageProps }: AppProps) {
        return <Component {...pageProps} />
    }
    export default MyApp

En el caso de que lo usemos par crear un layout debe ser de la siguiente manera (suponiendo que el layout es el mismo para todas las p谩ginas):
Layout.tsx:

import React from 'react';

    const Layout: React.FC = ({children}) => {
        <>
            <nav>
                <ul>
                    <li>Home</li>
                    <li>About</li>
                    <li>Contact</li>
                </ul>
            </nav>
            {children}
            <footer>
                All rights reserved
            </footer>
        </>
    }

    export default HomePage

App.tsx:

import { AppProps } from 'next/app'
    import Layout from './Layout'

    function MyApp({ Component, pageProps }: AppProps) {

        return (
            <Layout>
                <Component {...pageProps} />
            </Layout>
        )
    }

    export default MyApp

Qu茅 pasa si para ciertas p谩ginas deseemos usar un layout diferente? Como por ej, signup, login, splash screen, etc.
Para eso, tenemos que modificar el comportamiento de nuestro archivo _app por lo siguiente:

 import DefaultLayout from "../layouts/default"

    export default function MyApp({ Component, pageProps }) {
    // Use the layout defined at the page level, if available

    const getLayout = Component.getLayout || ((page) => <DefaultLayout>{page}</DefaultLayout>)

    return getLayout(<Component {...pageProps} />)
    }

Aqu铆 estamos diciendo que, si en el componente que se esta renderizando no hay un m茅todo 鈥榞etLayout鈥, nos renderice un layout por defecto. Sin embargo, podemos usar un layout diferente con el m茅todo getLayout en la p谩gina que queramos, ahora que modificamos el _app:

Login.tsx

        import React from 'react'
        import InitialLayout from '../layouts/initial'

        function Login() {
            return (
                <div>Login</div>
            )
        }

        Login.getLayout = (page) => {
            return (
                <InitialLayout>{page}</InitialLayout>
            )
        }

        export default Login;

El Login page, utiliza un m茅todo getLayout, que recibe el contenido de este, para que funcione debemos retornar un JSX, del layout deseado conteniendo al contenido de la p谩gina, que es el par谩metro que recibe esta funci贸n.

RESUMEN: Para crear contenido global de nuestra aplicaci贸n, es recomendable extender el app de next

Jon! te fuiste un nivel .mas arriba del necesario para importar en NavBar

se podria hacer, ../Navbar/Navbar directamente.

nada una boludez

import React, { ReactNode } from 'react';
import NavBar from '../Navbar/Navbar';

interface Props {
    children: ReactNode;
}

const Layout = ({children}: Props) => {
    return(
        <div>
            <NavBar />
            {children}
            <footer>soy el pie de pagina</footer>
        </div>
    );
}

export default Layout;```

tambien lo podemos hacer de la siguiente forma :D

Si est谩s usando TypeScript este es el c贸digo que pegas en el _app.tsx:

import type { AppProps } from 'next/app'

export default function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

En el archivo _app.js yo he inyectado React Conext Providers dependiendo de la ruta. Aun ando aprendiendo del todo Next.js pero ha sido muy uutil esto de extender la funcionalidad de los componentes

Aca les dejo la documentaci贸n oficial para los que lo est茅n haciendo en las 煤ltimas versiones.

https://nextjs.org/docs/getting-started/installation#creating-directories

Si les marca error el children, solo tienen que tiparlo mediante una interface:

interface Props {
  title: string;
  children: JSX.Element
}

Despu茅s solo extienden el FC:

const Layout: FC<Props> = ({ children, title }) => {}

De forma explicita (sin usar React.FC) c贸digo en el layout:

import React from "react";
import { Navbar } from '../Navbar';
type Props = {
  children?: JSX.Element;
};
function Layout({children}: Props) {
  return (
    <div>
      <Navbar />
      {children}
      <footer>This is the footer</footer>
    </div>
  )
}
export { Layout }

Para quien tenga el error 鈥樷楥omponent鈥 cannot be used as a JSX component鈥, la soluci贸n es actualizar las dependencias de tipos de React a la versi贸n 18.0.6.

el document en Typescript ahora es asi:

import Document, { DocumentContext, DocumentInitialProps } from 'next/document'

class MyDocument extends Document {
  static async getInitialProps(
    ctx: DocumentContext
  ): Promise<DocumentInitialProps> {
    const initialProps = await Document.getInitialProps(ctx)

    return initialProps
  }
}

export default MyDocument

Actualmente la documentacion recomienda para typescrip el siguiente codigo

https://nextjs.org/docs/basic-features/typescript#custom-app

import type { AppProps } from 'next/app'

export default function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

Dejo este articulo con ejemplos interesantes
https://jools.dev/nextjs-_appjs-example

Todo lo que pasen por las props del tag component queda disponible en las props de todos los hijos (es decir, de todos los componentes de la app:

return(
          <Component {...pageProps} globalProp={algo} otraGlobalProp={otroAlgo} />
    )

_app.tsx

// import App from 'next/app'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

// Only uncomment this method if you have blocking data requirements for
// every single page in your application. This disables the ability to
// perform automatic static optimization, causing every page in your app to
// be server-side rendered.
//
// MyApp.getInitialProps = async (appContext) => {
//   // calls page's `getInitialProps` and fills `appProps.pageProps`
//   const appProps = await App.getInitialProps(appContext);
//
//   return { ...appProps }
// }

export default MyApp