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?
@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.
typeof window !== 'undefined'
vez de apenas process.browser
? É mais detalhado, então, se não houver motivo aqui, prefiro usar process.browser
.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.
Comentários muito úteis
@vanniewelt Você sempre pode olhar para
process.browser
..editar por @Timer :
@vanniewelt Você sempre pode olhar para
typeof window
..