Next.js: Q : Comment exécuter du code côté client uniquement

Créé le 5 juil. 2017  ·  19Commentaires  ·  Source: vercel/next.js

J'ai une route de rappel dans mon application qui reçoit le jeton d'accès du processus d'authentification dans le fragment de hachage d'URL. J'aimerais l'analyser et l'enregistrer dans le magasin redux. J'avais l'habitude de passer par window.location.hash avant de passer au suivant, mais ce n'est pas disponible lorsque la page est rendue côté serveur (de plus, le fragment de hachage n'est apparemment pas envoyé au serveur, donc je ne peux pas l'analyser là-bas ).

Existe-t-il un moyen de restreindre certains codes à exécuter uniquement côté client ? Ou y a-t-il un autre moyen d'y parvenir?

Commentaire le plus utile

@vanniewelt Vous pouvez toujours regarder process.browser ..

if (process.browser) {
  // client-side-only code
}

édité par @Timer :

@vanniewelt Vous pouvez toujours regarder typeof window ..

if (typeof window !== 'undefined') {
  // client-side-only code
}

Tous les 19 commentaires

@vanniewelt : Le composant

Le cycle de vie de ComponentWillReceiveProps recevra également une demande dans les accessoires côté serveur.
Peut mettre vérifier si cette variable existe et injecter votre code client.

Si la lib a besoin d'une variable de fenêtre, je vous suggère d'utiliser les importations dynamiques, cela fonctionne bien pour moi.

https://github.com/zeit/next.js/tree/v3-beta/examples/with-dynamic-import

Vous pouvez également utiliser la méthode de cycle componentDidMount vie

@vanniewelt Vous pouvez toujours regarder process.browser ..

if (process.browser) {
  // client-side-only code
}

édité par @Timer :

@vanniewelt Vous pouvez toujours regarder typeof window ..

if (typeof window !== 'undefined') {
  // client-side-only code
}

oui mais ce n'est pas la meilleure approche.
disons que je veux vérifier si l'utilisateur est authentifié, et je veux exécuter cette vérification uniquement du côté client pour plusieurs raisons, l'une d'entre elles est parce que je stocke JWT dans localStorage et que je ne veux pas le stocker dans un cookie.
Donc dans ce cas sur la première page chargez avec :

if (process.browser) {
  // client-side-only code
}

le code dans la portée ne sera pas du tout exécuté, ni sur le serveur ni sur le client, il ne sera exécuté que si le changement de routage a été déclenché à partir du client

@sarkistlt Vous pouvez avoir raison dans certains cas selon l'endroit où ce code est placé .. mais ..

Si ce code est exécuté sur le serveur, l'exécution n'atteindra pas // client-side-only code . Si ce code est exécuté sur le client, l' exécution atteindra // client-side-only code .

Cela semble être une réponse valable à la question:

Existe-t-il un moyen de restreindre certains codes à exécuter uniquement côté client ?

@sarkistlt componentDidMount n'est exécuté que côté client, componentWillMount est exécuté à la fois côté client et côté serveur.

@sarkistlt https://reactjs.org/docs/react-component.html#componentwillmount

Il s'agit du seul hook de cycle de vie appelé sur le rendu du serveur.

Je l'ai fait plusieurs fois, vous confondez componentWillMount avec componentDidMount .

@sergiodxa en fait, vous avez raison, vous venez de faire le test. Merci!

Le lien componentWillMount @sergiodxa componentWillMount est remplacé par https://reactjs.org/docs/react-component.html#unsafe_componentwillmount.

J'avais besoin du module mapbox-gl qui est une bibliothèque côté client à l'intérieur de ComponentDidMount et je me suis débarrassé d'une vilaine erreur ReferenceError: self is not defined

Je n'ai pas pu créer Mapbox en utilisant componentDidMount car le composant essaie toujours d'être traité (je ne sais pas exactement ce qu'il essaie de faire) sur le serveur (j'ai fini par avoir le même problème que @elaich ).

L'utilisation des importations dynamiques comme suggéré par @aga5tya a fait l'affaire .

@vanniewelt : Le composant

Le cycle de vie de ComponentWillReceiveProps recevra également une demande dans les accessoires côté serveur.
Peut mettre vérifier si cette variable existe et injecter votre code client.

Si la lib a besoin d'une variable de fenêtre, je vous suggère d'utiliser les importations dynamiques, cela fonctionne bien pour moi.

https://github.com/zeit/next.js/tree/v3-beta/examples/with-dynamic-import

Pour ceux qui ont rencontré ce fil à la recherche de la solution. Le lien d'importations dynamiques répertorié ci-dessus est rompu. Il a été mis à jour et peut être trouvé sur Importations dynamiques .

Si vous avez un composant qui est toujours censé être exécuté sur le client et que vous ne voulez pas utiliser les importations dynamiques (par exemple, les gens peuvent oublier qu'ils ont besoin de les utiliser), vous pouvez utiliser des Hooks (ou l'équivalent componentDidMount ) comme suit :

import React, { useEffect, useState } from 'react'

function CreateInteraction ({ input }) {
  const [isComponentMounted, setIsComponentMounted] = useState(false)

  useEffect(() => setIsComponentMounted(true), [])

  if(!isComponentMounted) {
    return null
  }

  return <h1>I'm only executed on the client!</h1>
}

Juste pour ajouter quelques réponses déjà bonnes : mon projet actuel fait beaucoup de rendu conditionnel dans les deux sens, j'utilise donc un composant pour cela :

import React, { useEffect, useState } from "react";

export interface ConditionallyRenderProps {
    client?: boolean;
    server?: boolean;
}

const ConditionallyRender: React.FC<ConditionallyRenderProps> = (props) => {
    const [isMounted, setIsMounted] = useState(false);

    useEffect(() => setIsMounted(true), []);

    if(!isMounted && props.client) {
        return null;
    }

    if(isMounted && props.server) {
        return null;
    }

    return props.children as React.ReactElement;
};

export default ConditionallyRender;

Et puis l'utiliser comme suit :

<Layout>
    <ConditionallyRender server>
        <p>This is rendered only on server.</p>
    </ConditionallyRender>
    <ConditionallyRender client>
        <p>This is rendered only on client.</p>
    </ConditionallyRender>
</Layout>

Si vous utilisez une bibliothèque qui accède à l'API du navigateur, vous pouvez importer dynamiquement des modules avec SSR=false comme deuxième argument.
const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { ssr: false } )
https://nextjs.org/docs/advanced-features/dynamic-import

Si vous utilisez une bibliothèque qui accède à l'API du navigateur, vous pouvez importer dynamiquement des modules avec SSR=false comme deuxième argument.
const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { ssr: false } )
https://nextjs.org/docs/advanced-features/dynamic-import

Vous devrez également ajouter cette importation si vous souhaitez utiliser l'importation "dynamique" pour quiconque consulte le code @yashwant-dangi !

import dynamic from 'next/dynamic'

@Timer J'ai remarqué que vous avez modifié mon commentaire https://github.com/vercel/next.js/issues/2473#issuecomment -362119102, que j'ai à nouveau modifié pour refléter le commentaire d'origine et votre modification.

  1. Pourquoi devrions-nous utiliser typeof window !== 'undefined' au lieu de seulement process.browser ? C'est plus détaillé, donc s'il n'y a pas de raison ici, je préfère utiliser process.browser .
  2. La prochaine fois que vous modifierez un commentaire de contributeur, pourriez-vous rendre la modification apparente dans votre commentaire ? Tout d'abord, cela peut rendre le fil déroutant, comme ici, où le commentaire suivant est une réponse à mon commentaire spécifique. Deuxièmement, c'est trompeur puisque ce n'est pas ce que j'ai écrit, et ce n'est pas non plus ce que les gens lisaient quand ils faisaient leur réaction.

Pourquoi devrions-nous utiliser typeof window !== 'undefined' au lieu de simplement process.browser ? C'est plus détaillé, donc s'il n'y a pas de raison ici, je préfère utiliser process.browser.

process.browser n'est pas standard et n'est disponible que dans l'environnement webpack, ce qui signifie qu'il est susceptible de casser à l'avenir, par exemple, webpack 5 ne polyremplit plus process .

Une alternative à typeof window !== "undefined" pourrait être Object.prototype.isPrototypeOf(window) . Sur la base de cet article , cependant, les bundles produits par Next.js détectent le précédent et tout ce qui produit des bundles plus légers doit être considéré comme une victoire.

Cette page vous a été utile?
0 / 5 - 0 notes