Next.js: P: Como executar código apenas do lado do cliente

Criado em 5 jul. 2017  ·  19Comentários  ·  Fonte: vercel/next.js

Eu tenho uma rota de retorno de chamada em meu aplicativo que recebe token de acesso do processo de autenticação no fragmento hash de URL. Eu gostaria de analisá-lo e salvá-lo na loja redux. Eu costumava passar por window.location.hash antes de mudar para o próximo, mas isso não está disponível quando a página renderiza do lado do servidor (também o fragmento hash aparentemente não é enviado ao servidor, então não posso analisá-lo lá )

Existe alguma maneira de restringir a execução de algum código apenas no lado do cliente? Ou existe alguma outra maneira de conseguir isso?

Comentários muito úteis

@vanniewelt Você sempre pode olhar para process.browser ..

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

editar por @Timer :

@vanniewelt Você sempre pode olhar para typeof window ..

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

Todos 19 comentários

@vanniewelt : O componente Async importado dinamicamente carrega no cliente e você pode colocar toda a lógica do lado do cliente lá.

Além disso, o ciclo de vida de ComponentWillReceiveProps receberá solicitação nos props enquanto estiver no lado do servidor.
Pode colocar verificar se esta variável existe e injetar seu código de cliente.

Se a lib precisa de variável de janela, sugiro que você use importações dinâmicas, funciona bem para mim.

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

Você também pode usar o método de ciclo de vida componentDidMount do React. Não é chamado de lado do servidor.

@vanniewelt Você sempre pode olhar para process.browser ..

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

editar por @Timer :

@vanniewelt Você sempre pode olhar para typeof window ..

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

sim, mas não é a melhor abordagem.
Digamos que eu queira verificar se o usuário está autenticado e executar essa verificação apenas no lado do cliente por vários motivos, um deles é porque estou armazenando JWT em localStorage e não quero armazená-lo em um cookie.
Portanto, neste caso, no carregamento da primeira página com:

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

o código dentro do escopo não será executado de forma alguma, nem no servidor nem no cliente, ele será executado apenas se a mudança de rota for acionada do cliente

@sarkistlt Você pode estar certo em alguns casos, dependendo de onde o código está colocado .. mas ..

Se esse código for executado no servidor, a execução não alcançará // client-side-only code . Se esse código é executado no cliente, execução chegará // client-side-only code .

Parece uma resposta válida para a pergunta:

Existe alguma maneira de restringir a execução de algum código apenas no lado do cliente?

@sarkistlt componentDidMount é executado apenas no lado do cliente, componentWillMount é executado no lado do cliente e no servidor.

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

Este é o único gancho de ciclo de vida chamado na renderização do servidor.

Eu fiz isso várias vezes, você está confundindo componentWillMount com componentDidMount .

@sergiodxa na verdade você está certo, acabou de fazer o teste. obrigado!

O link de @sergiodxa componentWillMount foi alterado para https://reactjs.org/docs/react-component.html#unsafe_componentwillmount.

Eu solicitei o módulo mapbox-gl , que é uma biblioteca do lado do cliente dentro de ComponentDidMount e me livrei de um erro feio ReferenceError: self is not defined

Não consegui fazer o Mapbox usando componentDidMount porque o componente ainda tenta ser processado (não sei exatamente o que está tentando fazer) no servidor (acabei tendo o mesmo problema que @elaich )

O uso de importações dinâmicas, conforme sugerido por @ aga5tya ,

@vanniewelt : O componente Async importado dinamicamente carrega no cliente e você pode colocar toda a lógica do lado do cliente lá.

Além disso, o ciclo de vida de ComponentWillReceiveProps receberá solicitação nos props enquanto estiver no lado do servidor.
Pode colocar verificar se esta variável existe e injetar seu código de cliente.

Se a lib precisa de variável de janela, sugiro que você use importações dinâmicas, funciona bem para mim.

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

Para aqueles que se depararam com este tópico em busca da solução. O link de importações dinâmicas listado acima está quebrado. Ele foi atualizado e pode ser encontrado em Dynamic Imports .

Se você tem um componente que sempre deve ser executado no cliente e não deseja usar importações dinâmicas (por exemplo: as pessoas podem esquecer que precisam usá-los), você pode usar ganchos (ou o equivalente componentDidMount ) da seguinte forma:

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

Apenas para adicionar algumas respostas que já são boas: Meu projeto atual faz muita renderização condicional em ambas as direções, então eu uso um componente para isso:

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;

Em seguida, use-o da seguinte maneira:

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

Se você estiver usando qualquer biblioteca que acessa a API do navegador, poderá importar módulos dinamicamente com SSR = false como segundo argumento.
const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { ssr: false } )
https://nextjs.org/docs/advanced-features/dynamic-import

Se você estiver usando qualquer biblioteca que acessa a API do navegador, poderá importar módulos dinamicamente com SSR = false como segundo argumento.
const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { ssr: false } )
https://nextjs.org/docs/advanced-features/dynamic-import

Você também precisará adicionar esta importação se quiser usar a importação "dinâmica" para qualquer pessoa que esteja procurando no código @ yashwant-dangi!

import dynamic from 'next/dynamic'

@Timer Percebi que você editou meu comentário https://github.com/vercel/next.js/issues/2473#issuecomment -362119102, que editei novamente para refletir o comentário original e sua edição.

  1. Por que devemos usar typeof window !== 'undefined' vez de apenas process.browser ? É mais detalhado, então, se não houver motivo aqui, prefiro usar process.browser .
  2. Na próxima vez que você editar um comentário de um colaborador, você poderia deixar a edição aparente em seu comentário? Em primeiro lugar, pode tornar o tópico confuso, como fez aqui, onde o comentário a seguir é uma resposta ao meu comentário específico. Em segundo lugar, é enganoso, uma vez que não foi isso que eu escrevi, e também não é o que as pessoas lêem quando fazem sua reação.

Por que devemos usar typeof window! == 'undefined' em vez de apenas process.browser? É mais detalhado, então, se não houver motivo aqui, prefiro usar process.browser.

process.browser não é padrão e está disponível apenas no ambiente webpack, o que significa que provavelmente será interrompido no futuro, por exemplo, o webpack 5 não mais polyfills process .

Uma alternativa para typeof window !== "undefined" poderia ser Object.prototype.isPrototypeOf(window) . Com base nesta postagem , no entanto, os pacotes produzidos por Next.js detectam o anterior e tudo o que produz pacotes mais leves deve ser considerado uma vitória.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

irrigator picture irrigator  ·  3Comentários

havefive picture havefive  ·  3Comentários

jesselee34 picture jesselee34  ·  3Comentários

sospedra picture sospedra  ·  3Comentários

DvirSh picture DvirSh  ·  3Comentários