Next.js: T: Bagaimana cara mengeksekusi kode hanya di sisi klien

Dibuat pada 5 Jul 2017  ·  19Komentar  ·  Sumber: vercel/next.js

Saya memiliki rute panggilan balik di aplikasi saya yang menerima token akses dari proses auth di fragmen hash URL. Saya ingin menguraikannya dan menyimpannya ke toko redux. Saya dulu mendapatkannya melalui window.location.hash sebelum saya beralih ke berikutnya, tetapi ini tidak tersedia ketika halaman merender sisi server (juga fragmen hash tampaknya tidak dikirim ke server, jadi saya tidak dapat menguraikannya di sana ).

Apakah ada cara untuk membatasi beberapa kode untuk dieksekusi hanya di sisi klien? Atau adakah cara lain untuk mencapai ini?

Komentar yang paling membantu

@vanniewelt Anda selalu dapat melihat process.browser ..

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

diedit oleh @Timer :

@vanniewelt Anda selalu dapat melihat typeof window ..

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

Semua 19 komentar

@vanniewelt : Komponen Async yang diimpor secara dinamis dimuat pada klien dan Anda dapat meletakkan semua logika sisi klien di sana.

Siklus hidup ComponentWillReceiveProps juga akan menerima permintaan di props saat berada di sisi server.
Dapat memeriksa apakah variabel ini ada dan menyuntikkan kode klien Anda.

Jika lib membutuhkan variabel jendela, saya sarankan Anda menggunakan impor Dinamis, berfungsi dengan baik untuk saya.

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

Anda juga dapat menggunakan metode siklus hidup componentDidMount dari React. Itu tidak disebut sisi server.

@vanniewelt Anda selalu dapat melihat process.browser ..

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

diedit oleh @Timer :

@vanniewelt Anda selalu dapat melihat typeof window ..

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

ya tapi itu bukan pendekatan terbaik.
katakanlah saya ingin memeriksa apakah pengguna diautentikasi, dan saya ingin menjalankan pemeriksaan itu hanya di sisi klien karena beberapa alasan, salah satunya adalah karena saya menyimpan JWT di localStorage dan tidak ingin menyimpannya di cookie.
Jadi dalam hal ini pada halaman pertama memuat dengan:

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

kode dalam ruang lingkup tidak akan dieksekusi sama sekali, bukan di server bukan di klien, itu akan dieksekusi hanya jika perubahan rute dipicu dari klien

@sarkistlt Anda mungkin benar dalam beberapa kasus tergantung di mana kode itu ditempatkan .. tapi..

Jika kode tersebut dieksekusi di server, eksekusi tidak akan mencapai // client-side-only code . Jika kode tersebut dieksekusi pada klien, eksekusi akan mencapai // client-side-only code .

Sepertinya jawaban yang valid untuk pertanyaan:

Apakah ada cara untuk membatasi beberapa kode untuk dieksekusi hanya di sisi klien?

@sarkistlt componentDidMount hanya dieksekusi sisi klien, componentWillMount dijalankan baik sisi klien maupun server.

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

Ini adalah satu-satunya kait siklus hidup yang dipanggil pada rendering server.

Saya melakukannya berkali-kali, Anda membingungkan componentWillMount dengan componentDidMount .

@sergiodxa sebenarnya Anda benar, baru saja menjalankan tes. Terima kasih!

Tautan @sergiodxa componentWillMount diubah menjadi https://reactjs.org/docs/react-component.html#unsafe_componentwillmount.

Saya membutuhkan modul mapbox-gl yang merupakan perpustakaan sisi klien di dalam ComponentDidMount dan menghilangkan kesalahan jelek ReferenceError: self is not defined

Saya tidak dapat membuat Mapbox menggunakan componentDidMount karena komponen masih mencoba untuk diproses (saya tidak tahu apa yang sebenarnya coba dilakukan) di server (saya akhirnya mengalami masalah yang sama dengan @elaich ).

Menggunakan Impor Dinamis seperti yang disarankan oleh @aga5tya berhasil .

@vanniewelt : Komponen Async yang diimpor secara dinamis dimuat pada klien dan Anda dapat meletakkan semua logika sisi klien di sana.

Siklus hidup ComponentWillReceiveProps juga akan menerima permintaan di props saat berada di sisi server.
Dapat memeriksa apakah variabel ini ada dan menyuntikkan kode klien Anda.

Jika lib membutuhkan variabel jendela, saya sarankan Anda menggunakan impor Dinamis, berfungsi dengan baik untuk saya.

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

Bagi mereka yang mengalami utas ini mencari solusi. Tautan Impor Dinamis yang tercantum di atas rusak. Ini telah diperbarui dan dapat ditemukan di Dynamic Imports .

Jika Anda memiliki komponen yang seharusnya selalu dijalankan pada klien, dan tidak ingin menggunakan Impor Dinamis (misalnya: orang dapat lupa bahwa mereka perlu menggunakannya), Anda dapat menggunakan Hooks (atau componentDidMount setara

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

Hanya untuk menambahkan beberapa jawaban yang sudah bagus: Proyek saya saat ini melakukan banyak rendering bersyarat di kedua arah, jadi saya menggunakan komponen untuk ini:

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;

Dan kemudian gunakan sebagai berikut:

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

Jika Anda menggunakan perpustakaan apa pun yang mengakses API browser, maka Anda dapat mengimpor modul secara dinamis dengan SSR=false sebagai argumen kedua.
const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { ssr: false } )
https://nextjs.org/docs/advanced-features/dynamic-import

Jika Anda menggunakan perpustakaan apa pun yang mengakses API browser, maka Anda dapat mengimpor modul secara dinamis dengan SSR=false sebagai argumen kedua.
const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { ssr: false } )
https://nextjs.org/docs/advanced-features/dynamic-import

Anda juga perlu menambahkan impor ini jika Anda ingin menggunakan impor "dinamis" untuk siapa pun yang melihat kode @yashwant-dangi!

import dynamic from 'next/dynamic'

@Timer Saya perhatikan Anda mengedit komentar saya https://github.com/vercel/next.js/issues/2473#issuecomment -362119102, yang saya edit lagi untuk mencerminkan komentar asli dan hasil edit Anda.

  1. Mengapa kita harus menggunakan typeof window !== 'undefined' bukan hanya process.browser ? Ini lebih bertele-tele, jadi jika tidak ada alasan di sini, saya lebih suka menggunakan process.browser .
  2. Lain kali Anda mengedit komentar kontributor, dapatkah Anda membuat pengeditan terlihat jelas di komentar Anda? Pertama, itu bisa membuat utas membingungkan, seperti yang terjadi di sini, di mana komentar berikut adalah balasan untuk komentar spesifik saya. Kedua, itu menyesatkan karena bukan itu yang saya tulis, dan juga bukan itu yang dibaca orang ketika mereka bereaksi.

Mengapa kita harus menggunakan typeof window !== 'undefined' bukan hanya process.browser? Ini lebih bertele-tele, jadi jika tidak ada alasan di sini, saya lebih suka menggunakan process.browser.

process.browser tidak standar dan hanya tersedia di lingkungan webpack, artinya kemungkinan akan rusak di masa mendatang, misalnya webpack 5 tidak lagi polyfills process .

Alternatif untuk typeof window !== "undefined" bisa menjadi Object.prototype.isPrototypeOf(window) . Berdasarkan posting ini , bagaimanapun, bundel yang diproduksi oleh Next.js mendeteksi bundel sebelumnya dan apa pun yang menghasilkan bundel yang lebih ringan harus dianggap sebagai kemenangan.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat