Next.js: F: So führen Sie Code nur clientseitig aus

Erstellt am 5. Juli 2017  ·  19Kommentare  ·  Quelle: vercel/next.js

Ich habe eine Rückrufroute in meiner Anwendung, die das Zugriffstoken vom Authentifizierungsprozess im URL-Hash-Fragment empfängt. Ich möchte es analysieren und im Redux Store speichern. Ich habe es durch window.location.hash bevor ich zum nächsten gewechselt habe, aber dies ist nicht verfügbar, wenn die Seite serverseitig gerendert wird (auch das Hash-Fragment wird anscheinend nicht an den Server gesendet, daher kann ich es dort nicht parsen ).

Gibt es eine Möglichkeit, Code so einzuschränken, dass er nur auf der Clientseite ausgeführt wird? Oder gibt es eine andere Möglichkeit, dies zu erreichen?

Hilfreichster Kommentar

@vanniewelt Du kannst dir immer process.browser anschauen..

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

von @Timer bearbeiten:

@vanniewelt Du kannst dir immer typeof window anschauen..

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

Alle 19 Kommentare

@vanniewelt : Dynamisch importierte Async-Komponenten werden auf dem Client geladen und Sie können die gesamte clientseitige Logik dort ablegen.

Auch der Lebenszyklus von ComponentWillReceiveProps empfängt Anforderungen in Requisiten, während er sich auf der Serverseite befindet.
Kann überprüfen, ob diese Variable existiert und Ihren Client-Code einfügen.

Wenn die Bibliothek eine Fenstervariable benötigt, schlage ich vor, dass Sie dynamische Importe verwenden, funktioniert gut für mich.

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

Sie können auch die Lebenszyklusmethode componentDidMount von React verwenden. Es heißt nicht serverseitig.

@vanniewelt Du kannst dir immer process.browser anschauen..

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

von @Timer bearbeiten:

@vanniewelt Du kannst dir immer typeof window anschauen..

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

ja, aber das ist nicht der beste Ansatz.
Nehmen wir an, ich möchte überprüfen, ob der Benutzer authentifiziert ist, und ich möchte diese Überprüfung aus mehreren Gründen nur auf der Clientseite ausführen. Einer davon ist, dass ich JWT in localStorage speichere und es nicht in einem Cookie speichern möchte.
Also in diesem Fall auf der ersten Seite laden mit:

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

Code innerhalb des Geltungsbereichs wird überhaupt nicht ausgeführt, nicht auf dem Server, nicht auf dem Client, er wird nur ausgeführt, wenn der Router-Wechsel vom Client ausgelöst wurde

@sarkistlt Möglicherweise

Wenn dieser Code auf dem Server ausgeführt wird, erreicht die Ausführung nicht // client-side-only code . Wenn dieser Code auf dem Client ausgeführt wird, wird die Ausführung erreicht // client-side-only code .

Es scheint eine gültige Antwort auf die Frage zu sein:

Gibt es eine Möglichkeit, Code so einzuschränken, dass er nur auf der Clientseite ausgeführt wird?

@sarkistlt componentDidMount wird nur clientseitig ausgeführt, componentWillMount wird sowohl client- als auch serverseitig ausgeführt.

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

Dies ist der einzige Lifecycle-Hook, der beim Server-Rendering aufgerufen wird.

Ich habe es oft gemacht, Sie verwechseln componentWillMount mit componentDidMount .

@sergiodxa eigentlich hast du recht, habe gerade den Test durchgeführt. Danke!

Der Link componentWillMount @sergiodxa componentWillMount wird in https://reactjs.org/docs/react-component.html#unsafe_componentwillmount geändert

Ich habe das Modul mapbox-gl das eine clientseitige Bibliothek in ComponentDidMount und einen hässlichen Fehler beseitigt ReferenceError: self is not defined

Ich konnte Mapbox nicht mit componentDidMount erstellen, weil die Komponente immer noch versucht, auf dem Server verarbeitet zu werden (ich weiß nicht, was genau versucht wird) (ich hatte am Ende das gleiche Problem wie @elaich ).

Die Verwendung dynamischer Importe, wie von @aga5tya vorgeschlagen, hat den Trick gemacht 🎉.

@vanniewelt : Dynamisch importierte Async-Komponenten werden auf dem Client geladen und Sie können die gesamte clientseitige Logik dort ablegen.

Auch der Lebenszyklus von ComponentWillReceiveProps empfängt Anforderungen in Requisiten, während er sich auf der Serverseite befindet.
Kann überprüfen, ob diese Variable existiert und Ihren Client-Code einfügen.

Wenn die Bibliothek eine Fenstervariable benötigt, schlage ich vor, dass Sie dynamische Importe verwenden, funktioniert gut für mich.

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

Für diejenigen, die auf dieser Suche nach der Lösung auf diesen Thread gestoßen sind. Der oben aufgeführte Link für dynamische Importe ist defekt. Es wurde aktualisiert und ist unter Dynamische Importe zu finden .

Wenn Sie eine Komponente haben, die immer auf dem Client ausgeführt werden soll, und keine dynamischen Importe verwenden möchten (zB: die Leute können vergessen, dass sie sie verwenden müssen), können Sie Hooks (oder das Äquivalent componentDidMount ) wie folgt:

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>
}

Nur um einige bereits gute Antworten hinzuzufügen: Mein aktuelles Projekt führt viel bedingtes Rendering in beide Richtungen durch, daher verwende ich eine Komponente dafür:

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;

Und dann verwenden Sie es wie folgt:

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

Wenn Sie eine Bibliothek verwenden, die auf die Browser-API zugreift, können Sie Module mit SSR=false als zweitem Argument dynamisch importieren.
const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { ssr: false } )
https://nextjs.org/docs/advanced-features/dynamic-import

Wenn Sie eine Bibliothek verwenden, die auf die Browser-API zugreift, können Sie Module mit SSR=false als zweitem Argument dynamisch importieren.
const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { ssr: false } )
https://nextjs.org/docs/advanced-features/dynamic-import

Sie müssen diesen Import auch hinzufügen, wenn Sie den "dynamischen" Import für jeden verwenden möchten, der sich @yashwant-dangi-Code ansieht!

import dynamic from 'next/dynamic'

@Timer Ich habe bemerkt, dass Sie meinen Kommentar https://github.com/vercel/next.js/issues/2473#issuecomment -362119102 bearbeitet haben, den ich erneut bearbeitet habe, um den ursprünglichen Kommentar und Ihre Bearbeitung widerzuspiegeln.

  1. Warum sollten wir typeof window !== 'undefined' statt nur process.browser ? Es ist ausführlicher, also wenn es keinen Grund gibt, bevorzuge ich process.browser .
  2. Könnten Sie beim nächsten Bearbeiten eines Beitragskommentars die Änderung in Ihrem Kommentar sichtbar machen? Zunächst einmal kann es den Thread verwirrend machen, wie hier, wo der folgende Kommentar eine Antwort auf meinen spezifischen Kommentar ist. Zweitens ist es irreführend, da ich das nicht geschrieben habe, und das ist auch nicht das, was die Leute lesen, wenn sie ihre Reaktion abgeben.

Warum sollten wir typeof window !== 'undefined' statt nur process.browser verwenden? Es ist ausführlicher, wenn es also keinen Grund gibt, bevorzuge ich process.browser.

process.browser ist kein Standard und nur in der Webpack-Umgebung verfügbar, was bedeutet, dass es in Zukunft wahrscheinlich kaputt gehen wird, zB webpack 5 polyfills process nicht mehr.

Eine Alternative zu typeof window !== "undefined" könnte Object.prototype.isPrototypeOf(window) . Basierend auf diesem Beitrag erkennen jedoch Bundles, die von Next.js produziert werden, den vorherigen und was auch immer leichtere Bundles produziert, sollte als Gewinn betrachtet werden.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen