Fermer

janvier 1, 2024

Liés à l’interface utilisateur et à l’environnement (partie 2) / Blogs / Perficient


Dans partie 1 nous avons abordé certains principes fondamentaux de Next.js : les stratégies de rendu ainsi que les nuances de getStaticProps, getStaticPaths, getServerSideProps ainsi que la récupération de données.

Nous allons maintenant parler des éléments liés à l’interface utilisateur, tels que les mises en page, les styles et les polices, la diffusion de statistiques, ainsi que les variables dactylographiées et environnementales.

Prise en charge CSS intégrée

Importation de styles globaux

Pour ajouter des styles globaux, le tableau correspondant doit être importé dans le pages/_app.js déposer (faites attention au trait de soulignement) :

// pages/_app.js
import './style.css'

// This export is mandatory by default
export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />
}

Ces styles seront appliqués à toutes les pages et composants de l’application. Attention : pour éviter les conflits, les styles globaux ne peuvent être importés que dans pages/_app.js.

Lors de la création de l’application, tous les styles sont combinés dans un seul fichier CSS réduit.

Importer des styles depuis le node_modules annuaire

Les styles peuvent être importés depuis node_modulesvoici un exemple d’importation de styles globaux :

// pages/_app.js
import 'bootstrap/dist/css/bootstrap.min.css'

export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />
}

Exemple d’import de styles pour un composant tiers :

// components/Dialog.js
import { useState } from 'react'
import { Dialog } from '@reach/dialog'
import VisuallyHidden from '@reach/visually-hidden'
import '@reach/dialog/styles.css'

export function MyDialog(props) {
  const [show, setShow] = useState(false)
  const open = () => setShow(true)
  const close = () => setShow(false)

  return (
    <div>
      <button onClick={open} className="btn-open">Expand</button>
      <Dialog>
        <button onClick={close} className="btn-close">
          <VisuallyHidden>Collapse</VisuallyHidden>
          <span>X</span>
        </button>
        <p>Hello!</p>
      </Dialog>
    </div>
  )
}

Ajout de styles au niveau des composants

Next.js prend en charge Modules CSS hors de la boîte. Les modules CSS doivent être nommés comme [name].module.css. Ils créent une portée locale pour les styles correspondants, ce qui vous permet d’utiliser les mêmes noms de classe sans risque de collision. Un module CSS est importé en tant qu’objet (habituellement appelé styles) dont les clés sont les noms des classes correspondantes.

Exemple d’utilisation de modules CSS :

/* components/Button/Button.module.css */
.danger {
  background-color: red;
  color: white;
}
// components/Button/Button.js
import styles from './Button.module.css'

export const Button = () => (
  <button className={styles.danger}>
    Remove
  </button>
)

Une fois construits, les modules CSS sont concaténés et séparés en fichiers CSS minifiés distincts, ce qui vous permet de charger uniquement les styles nécessaires.

Prise en charge du SASS

Next.js prend en charge .scss et .sass des dossiers. SASS peut également être utilisé au niveau des composants (.module.scss et .module.sass). Pour compiler SASS en CSS, vous devez avoir installé SASS :

npm install sass

Le comportement du compilateur SASS peut être personnalisé dans le next.config.js fichier, par exemple :

const path = require('path')

module.exports = {
  sassOptions: {
    includePaths: [path.join(__dirname, 'styles')]
  }
}

CSS-en-JS

Vous pouvez utiliser n’importe quelle solution CSS-in-JS dans Next.js. L’exemple le plus simple consiste à utiliser des styles en ligne :

export const Hi = ({ name }) => <p style={{ color: 'green' }}>Hello, {name}!</p>

Next.js a également style-jsx prise en charge intégrée :

export const Bye = ({ name }) => (
  <div>
    <p>Bye, {name}. See you soon!</p>
    <style jsx>{`
      div {
        background-color: #3c3c3c;
      }
      p {
        color: #f0f0f0;
      }
      @media (max-width: 768px) {
        div {
          backround-color: #f0f0f0;
        }
        p {
          color: #3c3c3c;
        }
      }
    `}</style>
    <style global jsx>{`
      body {
        margin: 0;
        min-height: 100vh;
        display: grid;
        place-items: center;
      }
    `}</style>
  </div>
)

Mises en page

Développer une application React implique de diviser la page en composants distincts. De nombreux composants sont utilisés sur plusieurs pages. Supposons que chaque page utilise une barre de navigation et un pied de page :

// components/layout.js
import Navbar from './navbar'
import Footer from './footer'

export default function Layout({ children }) {
  return (
    <>
      <Navbar />
      <main>{children}</main>
      <Footer />
    </>
  )
}

Exemples

Disposition unique

Si une application n’utilise qu’une seule mise en page, nous pouvons créer une application personnalisée et envelopper l’application dans une mise en page. Puisque le composant de mise en page sera réutilisé lorsque les pages changent, son état (par exemple, les valeurs d’entrée) sera conservé :

// pages/_app.js
import Layout from '../components/layout'

export default function App({ Component, pageProps }) {
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  )
}

Dispositions au niveau de la page

Le getLayout La propriété d’une page permet de renvoyer un composant pour la mise en page. Cela vous permet de définir des mises en page au niveau de la page. La fonction renvoyée vous permet de construire des mises en page imbriquées :

// pages/index.js
import Layout from '../components/layout'
import Nested from '../components/nested'

export default function Page() {
  return {
    // ...
  }
}

Page.getLayout = (page) => (
  <Layout>
    <Nested>{page}</Nested>
  </Layout>
)

// pages/_app.js
export default function App({ Component, pageProps }) {
  // use the layout defined ata page level, if exists
  const getLayout = Component.getLayout || ((page) => page)

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

Lors du changement de page, l’état de chacune d’elles (valeurs d’entrée, position de défilement, etc.) sera enregistré.

Utilisez-le avec TypeScript

Lors de l’utilisation de TypeScript, un nouveau type est d’abord créé pour la page qui inclut getLayout. Vous devez ensuite créer un nouveau type pour AppProps qui écrase le Component propriété pour permettre l’utilisation du type créé précédemment :

// pages/index.tsx
import type { ReactElement } from 'react'
import Layout from '../components/layout'
import Nested from '../components/nested'

export default function Page() {
  return {
    // ...
  }
}

Page.getLayout = (page: ReactElement) => (
  <Layout>
    <Nested>{page}</Nested>
  </Layout>
)

// pages/_app.tsx
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'

type NextPageWithLayout = NextPage & {
  getLayout?: (page: ReactElement) => ReactNode
}

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout
}

export default function App({ Component, pageProps }: AppPropsWithLayout) {
  const getLayout = Component.getLayout ?? ((page) => page)

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

Récupération des données

Les données de la mise en page peuvent être récupérées côté client en utilisant useEffect ou des utilitaires comme SWR. La mise en page n’étant pas une page, elle ne peut actuellement pas utiliser getStaticProps ou getServerSideProps:

import useSWR from 'swr'
import Navbar from './navbar'
import Footer from './footer'

export default function Layout({ children }) {
  const { data, error } = useSWR('/data', fetcher)

  if (error) return <div>Error</div>
  if (!data) return <div>Loading...</div>

  return (
    <>
      <Navbar />
      <main>{children}</main>
      <Footer />
    </>
  )
}

Composant d’image et optimisation d’image

Le Image composant, importé de next/imageest une extension du img Balise HTML conçue pour le Web moderne. Il comprend plusieurs optimisations intégrées pour obtenir de bons Core Web Vitals performance. Ces optimisations incluent les éléments suivants :

  • amélioration des performances
  • assurer la stabilité visuelle
  • accélérer le chargement des pages
  • assurer la flexibilité (évolutivité) d’images

Exemple d’utilisation d’une image locale :

import Image from 'next/image'
import imgSrc from '../public/some-image.png'

export default function Home() {
  return (
    <>
      <h1>Home page</h1>
      <Image
        src={imgSrc}
        alt=""
        role="presentation"
      />
    </h1>
  )
}

Exemple d’utilisation d’une image distante (remarque que tu besoin pour définir la largeur et la hauteur de l’image) :

import Image from 'next/image'

export default function Home() {
  return (
    <>
      <h1>Home page</h1>
      <Image
        src="https://blogs.perficient.com/some-image.png"
        alt=""
        role="presentation"
        width={500}
        height={500}
      />
    </h1>
  )
}

Définir les dimensions de l’image

Image s’attend à recevoir la largeur et la hauteur de l’image :

  • dans le cas d’une importation statique (image locale), la largeur et la hauteur sont calculées automatiquement
  • la largeur et la hauteur peuvent être spécifiées à l’aide d’accessoires appropriés
  • si les dimensions de l’image sont inconnues, vous pouvez utiliser le layout accessoire avec le fill valeur

Il existe 3 façons de résoudre le problème des tailles d’image inconnues :

  • En utilisant fill mode mise en page : Ce mode permet de contrôler les dimensions de l’image à l’aide de l’élément parent. Dans ce cas, les dimensions de l’élément parent sont déterminées à l’aide de CSS et les dimensions de l’image sont déterminées à l’aide du object-fit et object-position propriétés
  • normalisation des images : si la source des images est sous notre contrôle, nous pouvons ajouter un redimensionnement à l’image lorsqu’elle est renvoyée en réponse à la requête
  • modification des appels API : la réponse à une requête peut inclure non seulement l’image elle-même mais aussi ses dimensions

Règles de stylisme des images :

  • choisissez le bon mode de mise en page
  • utiliser className – il est réglé sur le correspondant img élément. Veuillez noter: style l’accessoire n’est pas passé
  • lors de l’utilisation layout="fill" l’élément parent doit avoir position: relative
  • lors de l’utilisation layout="responsive" l’élément parent doit avoir display: block

Voir ci-dessous pour plus d’informations sur le composant Image.

Optimisation des polices

Next.js intègre automatiquement les polices dans CSS au moment de la construction :

// before
<link
  href="https://fonts.googleapis.com/css2?family=Inter"
  rel="stylesheet"
/>

// after
<style data-href="https://fonts.googleapis.com/css2?family=Inter">
  @font-face{font-family:'Inter';font-style:normal...}
</style>

Pour ajouter une police à la page, utilisez le Head composant, importé de next/head:

// pages/index.js
import Head from 'next/head'

export default function IndexPage() {
  return (
    <div>
      <Head>
        <link
          rel="stylesheet"
          href="https://fonts.googleapis.com/css2?family=Inter&display=optional"
        />
      </Head>
      <p>Hello world!</p>
    </div>
  )
}

Pour ajouter une police à l’application, vous devez créer un document personnalisé :

// pages/_document.js
import Document, { Html, Head, Main, NextScript } from 'next/document'

class MyDoc extends Document {
  render() {
    return (
      <Html>
        <Head>
          <link
            rel="stylesheet"
            href="https://fonts.googleapis.com/css2?family=Inter&display=optional"
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

L’optimisation automatique des polices peut être désactivée :

// next.config.js
module.exports = {
  optimizeFonts: false
}

Pour plus d’informations sur le composant Head, voir ci-dessous.

Composant de script

Le Script Le composant permet aux développeurs de prioriser le chargement de scripts tiers, ce qui permet de gagner du temps et d’améliorer les performances.

La priorité de chargement du script est déterminée à l’aide de la strategy prop, qui prend l’une des valeurs suivantes :

  • beforeInteractive: Il s’agit des scripts importants qui doivent être chargés et exécutés avant que la page ne devienne interactive. Ces scripts incluent, par exemple, la détection de robots et les demandes d’autorisation. Ces scripts sont intégrés dans le code HTML initial et exécutés avant le reste du JS.
  • afterInteractive: pour les scripts qui peuvent être chargés et exécutés une fois que la page est devenue interactive. Ces scripts incluent, par exemple, les gestionnaires de balises et les analyses. Ces scripts sont exécutés côté client et exécutés après hydratation
  • lazyOnload: pour les scripts qui peuvent être chargés pendant les périodes d’inactivité. Ces scripts incluent, par exemple, l’assistance par chat et les widgets de réseaux sociaux

Note:

  • Script prend en charge les scripts intégrés avec afterInteractive et lazyOnload stratégies
  • scripts en ligne enveloppés dans Script doit avoir un id attribut pour les suivre et les optimiser

Exemples

Veuillez noter: le Script Le composant ne doit pas être placé à l’intérieur d’un Head composant ou un document personnalisé.

Chargement des polyfills :

import Script from 'next/script'

export default function Home() {
  return (
    <>
      <Script
        src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver"
        strategy="beforeInteractive"
      />
    </>
  )
}

Chargement paresseux :

import Script from 'next/script'

export default function Home() {
  return (
    <>
      <Script
        src="https://connect.facebook.net/en_US/sdk.js"
        strategy="lazyOnload"
      />
    </>
  )
}

Exécution du code une fois la page entièrement chargée :

import { useState } from 'react'
import Script from 'next/script'

export default function Home() {
  const [stripe, setStripe] = useState(null)

  return (
    <>
      <Script
        id="stripe-js"
        src="https://js.stripe.com/v3/"
        onLoad={() => {
          setStripe({ stripe: window.Stripe('pk_test_12345') })
        }}
      />
    </>
  )
}

Scripts en ligne :

import Script from 'next/script'

<Script id="show-banner" strategy="lazyOnload">
  {`document.getElementById('banner').classList.remove('hidden')`}
</Script>

// or
<Script
  id="show-banner"
  dangerouslySetInnerHTML={{
    __html: `document.getElementById('banner').classList.remove('hidden')`
  }}
/>

Attributs de passage :

import Script from 'next/script'

export default function Home() {
  return (
    <>
      <Script
        src="https://www.google-analytics.com/analytics.js"
        id="analytics"
        nonce="XUENAJFW"
        data-test="analytics"
      />
    </>
  )
}

Servir des fichiers statiques

Les ressources statiques doivent être placées dans le public répertoire, situé dans le répertoire racine du projet. Fichiers situés dans le public l’annuaire est accessible via le lien de base /:

import Image from 'next/image'

export default function Avatar() {
  return <Image src="https://blogs.perficient.com/me.png" alt="me" width="64" height="64" >
}

Ce répertoire est également idéal pour stocker des fichiers tels que robots.txt, favicon.pngles fichiers nécessaires à la vérification du site Google et d’autres fichiers statiques (y compris .html).

Mise à jour en temps réel

Next.js prend en charge les mises à jour des composants en temps réel tout en conservant l’état local dans la plupart des cas (cela s’applique uniquement aux composants fonctionnels et aux crochets). L’état du composant est également conservé en cas d’erreurs (non lié au rendu) se produire.

Pour recharger un composant, il suffit d’ajouter // @refresh reset n’importe où.

Manuscrit

Next.js prend en charge TypeScript dès le départ. Il existe des types spéciaux GetStaticProps, GetStaticPaths et GetServerSideProps pour getStaticProps, getStaticPaths et getServerSideProps:

import { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next'

export const getStaticProps: GetStaticProps = async (context) => {
  // ...
}

export const getStaticPaths: GetStaticPaths = async () => {
  // ...
}

export const getServerSideProps: GetServerSideProps = async (context) => {
  // ...
}

Un exemple d’utilisation de types intégrés pour l’interface de routage (Itinéraires API) :

import type { NextApiRequest, NextApiResponse } from 'next'

export default (req: NextApiRequest, res: NextApiResponse) => {
  res.status(200).json({ message: 'Hello!' })
}

Rien ne nous empêche de saisir les données contenues dans la réponse :

import type { NextApiRequest, NextApiResponse } from 'next'

type Data = {
  name: string
}

export default (req: NextApiRequest, res: NextApiResponse<Data>) => {
  res.status(200).json({ message: 'Bye!' })
}

Next.js prend en charge paths et baseUrl paramètres définis dans tsconfig.json.

Variables d’environnement

Next.js prend en charge les variables d’environnement, ce qui vous permet d’effectuer les opérations suivantes :

utiliser .env.local charger des variables
extrapoler des variables au navigateur en utilisant le NEXT_PUBLIC_ préfixe

Supposons que nous ayons .env.local fichier, comme ci-dessous :

DB_HOST=localhost
DB_USER=myuser
DB_PASS=mypassword

Cela se chargera automatiquement process.env.DB_HOST, process.env.DB_USER et process.env.DB_PASS dans le runtime Node.js

// pages/index.js
export async function getStaticProps() {
  const db = await myDB.connect({
    host: process.env.DB_HOST,
    username: process.env.DB_USER,
    password: process.env.DB_PASS
  })

  // ...
}

Next.js vous permet d’utiliser des variables à l’intérieur .env des dossiers:

HOSTNAME=localhost
PORT=8080
HOST=http://$HOSTNAME:$PORT

Afin de transmettre une variable d’environnement au navigateur, vous devez ajouter le NEXT_PUBLIC_ préfixe:

NEXT_PUBLIC_ANALYTICS_ID=value
// pages/index.js
import setupAnalyticsService from '../lib/my-analytics-service'

setupAnalyticsService(process.env.NEXT_PUBLIC_ANALYTICS_ID)

function HomePage() {
  return <h1>Hello world!</h1>
}

export default HomePage

En plus de .env.localvous pouvez créer .env pour les deux modes, .env.development (pour le mode développement), et .env.production (pour le mode production) des dossiers. Veuillez noter: .env.local a toujours la priorité sur les autres fichiers contenant des variables d’environnement.

Ceci conclut la partie 2. Dans la partie 3, nous parlerons du routage avec Next.js – pages, routes API, mises en page, middleware et mise en cache.






Source link

janvier 1, 2024