Usar um componente funcional como filho de <Link/>
causa:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Isso aconteceu apenas após a atualização da v8 => v9.
Repo de reprodução: https://github.com/nickluger/nextjs-link-ref-functional-comp-warning
<Link/>
deve funcionar com componentes funcionais, também / não mostrar um aviso.
O mesmo aqui. Estou tendo um erro se usar um componente personalizado como este:
<Link href="/href">
<Button
type="custom"
color="#FCFCFC"
>
buttonText
</Button>
</Link>
Isso só acontece quando você usa um componente como filho. Eles não fornecem um aviso, por exemplo:
<Link href="/href">
<button
type="custom"
color="#FCFCFC"
>
buttonText
</button>
</Link>
<Link href="/href">
<a>
<Button
type="custom"
color="#FCFCFC"
>
buttonText
</Button>
</a>
</Link>
Existe uma maneira de contornar esse bug? estamos impedidos de ir para 9 para este, quando alguns recursos que realmente gostaríamos de aproveitar, como o suporte de digitação. Acabei de notar que atingiu 9.0.3: /
Você pode tentar silenciar temporariamente, como:
// TODO: Muting error, fix as soon as zeit/next.js/issues/7915 resolved
const originalError = console.error;
console.error = (...args) => {
if (/Warning.*Function components cannot be given refs/.test(args[0])) {
return;
}
originalError.call(console, ...args);
};
Estou tendo o mesmo problema aqui.
Se você usar <Link/>
para embrulhar seu componente personalizado, poderá encaminhar ref
assim:
const CustomComponent = React.forwardRef(function CustomComponent(props, ref) {
return (
<div/>
);
});
<Link href={"/"}>
<CustomComponent/>
</Link>
O aviso vai embora.
Eu atualizei para 9.0.4-canary.2
mas ainda recebo o aviso no console. Estou esquecendo de algo?
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Check the render method of `Link`.
@ th0th Você deve envolver seu componente em React.forwardRef
. Como este:
import React from 'react'
import Link from 'next/link'
const CustomComponent = React.forwardRef((props, ref) => (
<a ref={ref} {...props}>
Click
</a>
))
export default () => (
<Link href='/' passHref>
<CustomComponent/>
</Link>
)
Encapsular todos os componentes funcionais usados em Link
manualmente ? Não deveria haver uma solução mais fácil e menos repetitiva para isso? Pelo menos algo como <Link href="/" forwardRef>...</Link>
?
Concorde com @nickluger, isso parece contra-intuitivo.
Todas as outras bibliotecas devem implementar forwardRef
attribute da mesma maneira? Ou talvez os criadores da reação pensassem que os desenvolvedores usariam a função React.forwardRef
vez de implementar o atributo forwardRef
?
Sim, concordo com @nickluger , é uma dor fazer isso manualmente para todos os componentes dentro de um Link
.
Devemos reabrir e renomear este problema (@ijjk) ou alguém já abriu um novo?
O mesmo aqui. Estou tendo um erro se usar um componente personalizado como este:
<Link href="/href"> <Button type="custom" color="#FCFCFC" > buttonText </Button> </Link>
Isso só acontece quando você usa um componente como filho. Eles não fornecem um aviso, por exemplo:
<Link href="/href"> <button type="custom" color="#FCFCFC" > buttonText </button> </Link> <Link href="/href"> <a> <Button type="custom" color="#FCFCFC" > buttonText </Button> </a> </Link>
Isso provavelmente gerará um erro de console:
Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>.
Acabei de encontrar esse problema ao atualizar o Next JS. Existe uma correção no caminho?
Não tenho certeza se entendo como usar forwardRef e envolver meu componente. Meu arquivo button.js exporta atualmente o seguinte ....
const Button = (props) => {
return (<stuff />)
}
export default React.memo(Button)
Veja acima, abri um follow-up aqui: https://github.com/zeit/next.js/issues/8962
Acabei de encontrar esse problema ao atualizar o Next JS. Existe uma correção no caminho?
Não tenho certeza se entendo como usar forwardRef e envolver meu componente. Meu arquivo button.js exporta atualmente o seguinte ....
const Button = (props) => { return (<stuff />) } export default React.memo(Button)
Neste caso, você deve ser capaz de apenas fazer
import {forwardRef} from 'react';
const Button = forwardRef(props, ref) => {
return (<stuff ref={ref} />)
}
para a parte forwardRef. Os documentos também mencionam https://nextjs.org/docs#forcing -the-link-to-expose-href-to-its-child, embora eu não tenha tentado isso. Eu descobri que fazendo isso
<Link
href={href}
>
<a>
{text}
</a>
</Link>
funciona (apesar de parecer muito estranho.)
Encontrar este problema no 9.0.2
Usar <a></a>
ao redor pode funcionar, mas irá disparar outro erro como "deve ter href", etc. ao usar a11y e semelhantes.
Edit: Gastei 15 minutos tentando descobrir isso, é muito chato, uma grande perda de tempo, e parece se comportar corretamente, apesar do aviso.
Pessoalmente, acessar https://github.com/zeit/next.js/issues/7915#issuecomment -511792629 é muito mais fácil.
Que tal essa solução usando um fragmento de reação como um invólucro de rolamento?
import React, { Fragment, useRef } from 'react';
import { MyFunctionalComponent } from './my-functional-component';
const App = props => {
const myRef = useRef();
return (
<Link href={href}>
<Fragment>
<MyFunctionalComponent ref={myRef} />
</Fragment>
</Link>
);
}
Onde <MyFunctionalComponent>
encaminha a referência:
import React, { forwardRef } from 'react';
const MyFunctionalComponent = forwardRef(props, ref) => (
<div ref={ref} />
);
Isso não adiciona nenhum wrapper HTML adicional na saída ( <div />
) e não deve acionar nenhum erro relacionado.
@ hill84 Interessante, mas de onde myRef
vem em seu exemplo?
@Vadorequest Eu adicionei mais detalhes ao meu comentário anterior.
Seguir a sugestão de @ hill84 foi uma boa solução alternativa:
`` `
const ButtonLink: FC
<
Seguir a sugestão de @ hill84 foi uma boa solução alternativa:
const ButtonLink: FC<ButtonLinkProps> = ({ children, href, ...props }) => ( <Link href={href}> <><Button link {...props}>{children}</Button></> </Link> );
Eu uso <><Component/></>
mas o Link não pode agir. Tenho que usar <div></div>
vez de.
Eu sugiro uma solução em que uma função retorna um objeto com adereços em vez de um componente:
const propsUserBtn = user => ({
className: "h-10 w-10 font-black rounded-full bg-orange-200 text-teal-700",
title: user.first_name + ' ' + user.last_name,
children: (user.first_name.charAt(0) + user.last_name.charAt(0)).toUpperCase()
})
<Link href='/profile'>
<button { ...propsUserBtn(user) } />
</Link>
Verificado, funciona!
Por que este ref é mesmo necessário? É para garantir o posicionamento correto de href
no componente empacotado subjacente quando passHref
é usado em <Link />
?
Isso é muito irritante, pois meu componente personalizado <a>
na raiz e posso ver que está sendo href aplicado a ele corretamente de qualquer maneira ... Eu prefiro que seja imposto de que você precisa de seu componente personalizado subjacente tenha a âncora na raiz e evite toda essa ref
design desicion.
React.forwardRef
é uma coisa terrivelmente complicada de forçar as pessoas a implementar e está brincando com meus linters 😞
Ou, pelo menos, que seja um recurso opcional se você precisar especificar a colocação de href
em seu componente. <Link href="/" passHref useRef />
?
Não acho que ter que criar outro módulo para encaminhar o ref para um componente personalizado seja uma boa solução e também seja muito repetitivo.
A maneira que estou usando para lidar com esse problema é envolvendo o componente personalizado com um elemento div
, como sugerido por @ namlq93, mas também não parece estar limpo ...
O mesmo aqui. Estou tendo um erro se usar um componente personalizado como este:
<Link href="/href"> <Button type="custom" color="#FCFCFC" > buttonText </Button> </Link>
Isso só acontece quando você usa um componente como filho. Eles não fornecem um aviso, por exemplo:
<Link href="/href"> <button type="custom" color="#FCFCFC" > buttonText </button> </Link> <Link href="/href"> <a> <Button type="custom" color="#FCFCFC" > buttonText </Button> </a> </Link>
Funciona, obrigado amigo !!
Estou tendo um problema semelhante
ainda lá
https://nextjs.org/docs/api-reference/next/link#if -the-child-is-a-function-component
Isso é triste.
Eu estava assistindo a conferência NextJS outro dia pensando "Wow Next é o futuro". Eu realmente gosto do Next e do ecossistema Vercel e quero honestamente poder dizer isso e ser um defensor do Next. No entanto, questões como essas sendo fechadas e não tratadas tornam isso difícil. Já vi esse tipo de padrão várias vezes em todos os problemas aqui, especificamente com o Roteador.
Existem 3 soluções para este problema do lado do usuário e nenhuma delas é boa DX.
React.forwardRef
. Isso pode ser muito repetitivodiv
, span
, a
, etc.router.push
Não importa qual solução você use, eles são todos estranhos e requerem comentários com links para este problema ou os documentos para explicar aos colegas de trabalho / contribuidores por que é necessário evitar a remoção / limpeza acidental.
Acho que esse assunto deve ser reaberto para discussão.
Comentários muito úteis
Encapsular todos os componentes funcionais usados em
Link
manualmente ? Não deveria haver uma solução mais fácil e menos repetitiva para isso? Pelo menos algo como<Link href="/" forwardRef>...</Link>
?