Next.js: Siguiente 9 - Uso de componentes funcionales como hijo de<link/> provoca advertencias de referencia

Creado en 12 jul. 2019  ·  32Comentarios  ·  Fuente: vercel/next.js

Informe de error

Describe el error

El uso de un componente funcional como hijo de <Link/> provoca:

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Esto sucedió solo después de actualizar desde v8 => v9.

Reproducir

Repo de reproducción: https://github.com/nickluger/nextjs-link-ref-functional-comp-warning

Comportamiento esperado

<Link/> debería funcionar con componentes funcionales / no mostrar una advertencia.

Información del sistema

  • Versión de Next.js: 9.0.1
bug

Comentario más útil

Envuelva todos los componentes funcionales utilizados dentro de un Link manualmente ? ¿No debería haber una solución más fácil y menos repetitiva para esto? ¿Al menos algo como <Link href="/" forwardRef>...</Link> ?

Todos 32 comentarios

Igual que aquí. Tengo un error si uso un componente personalizado como este:

        <Link href="/href">
          <Button
            type="custom"
            color="#FCFCFC"
          >
             buttonText
          </Button>
        </Link>

Esto solo sucede cuando usa un componente cuando era niño. Estos no dan una advertencia, por ejemplo:

        <Link href="/href">
          <button
            type="custom"
            color="#FCFCFC"
          >
            buttonText
          </button>
        </Link>

        <Link href="/href">
          <a>
            <Button
              type="custom"
              color="#FCFCFC"
            >
              buttonText
            </Button>
          </a>
        </Link>

¿Hay alguna forma de evitar este error? estamos bloqueados para pasar al 9 para este cuando algunas características que realmente nos gustaría aprovechar como el soporte de mecanografiado. Acabo de notar que saltó a 9.0.3: /

Podría intentar silenciarlo temporalmente, 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);
};

Tengo el mismo problema aquí.

Si usa <Link/> para envolver su componente personalizado, podría reenviar ref así:

const CustomComponent = React.forwardRef(function CustomComponent(props, ref) {
  return (
    <div/>
  );
});
<Link href={"/"}>
  <CustomComponent/>
</Link>

La advertencia desaparece.

He actualizado a 9.0.4-canary.2 pero todavía recibo la advertencia en la consola. ¿Me estoy perdiendo 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 Debes envolver tu componente en React.forwardRef . Como éste:

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

Envuelva todos los componentes funcionales utilizados dentro de un Link manualmente ? ¿No debería haber una solución más fácil y menos repetitiva para esto? ¿Al menos algo como <Link href="/" forwardRef>...</Link> ?

De acuerdo con @nickluger, esto parece contrario a la intuición.

¿Todas las demás bibliotecas deberían implementar el atributo forwardRef de la misma manera? ¿O tal vez los creadores de Reacción pensaron que los desarrolladores usarían la función React.forwardRef lugar de implementar el atributo forwardRef ?

Sí, de acuerdo con @nickluger , es una molestia hacer esto manualmente para todos los componentes dentro de un Link .

¿Deberíamos reabrir y cambiar el nombre de este problema (@ijjk) o alguien ya abrió uno nuevo?

Igual que aquí. Tengo un error si uso un componente personalizado como este:

        <Link href="/href">
          <Button
            type="custom"
            color="#FCFCFC"
          >
             buttonText
          </Button>
        </Link>

Esto solo sucede cuando usa un componente cuando era niño. Estos no dan una advertencia, por ejemplo:

        <Link href="/href">
          <button
            type="custom"
            color="#FCFCFC"
          >
            buttonText
          </button>
        </Link>

        <Link href="/href">
          <a>
            <Button
              type="custom"
              color="#FCFCFC"
            >
              buttonText
            </Button>
          </a>
        </Link>

Lo más probable es que esto arroje un error de consola:

Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>.

Acabo de encontrar este problema al actualizar Next JS. ¿Hay alguna solución en el camino?

No estoy seguro de entender cómo usar forwardRef y envolver mi componente. Mi archivo button.js actualmente exporta lo siguiente ...

const Button = (props) => {
    return (<stuff />)
}

export default React.memo(Button)

Ver arriba, abrí un seguimiento aquí: https://github.com/zeit/next.js/issues/8962

Acabo de encontrar este problema al actualizar Next JS. ¿Hay alguna solución en el camino?

No estoy seguro de entender cómo usar forwardRef y envolver mi componente. Mi archivo button.js actualmente exporta lo siguiente ...

const Button = (props) => {
    return (<stuff />)
}

export default React.memo(Button)

En este caso, debería poder hacer

import {forwardRef} from 'react';
const Button = forwardRef(props, ref) => {
    return (<stuff ref={ref} />)
}

para la parte forwardRef. Los documentos también mencionan https://nextjs.org/docs#forcing -the-link-to-expose-href-to-its-child, aunque no lo he probado. He descubierto que haciendo esto

            <Link
              href={href}
            >
              <a>
                {text}
              </a>
            </Link>

funciona (a pesar de parecer muy extraño).

Encontrando este problema en 9.0.2

Usar <a></a> alrededor puede funcionar, pero desencadenará otro error como "debe tener href", etc. al usar a11y y similares.

Editar: Pasé 15 minutos tratando de resolver esto, es muy aburrido, una pérdida de tiempo y parece comportarse correctamente a pesar de la advertencia.

Personalmente, ir a https://github.com/zeit/next.js/issues/7915#issuecomment -511792629 es mucho más fácil.

¿Qué pasa con esta solución que usa un fragmento de reacción como envoltorio de cojinete?

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

Donde <MyFunctionalComponent> reenvía la referencia:

import React, { forwardRef } from 'react';

const MyFunctionalComponent = forwardRef(props, ref) => (
  <div ref={ref} />
);

Esto no agrega ningún contenedor HTML adicional en la salida ( <div /> ) y no debería desencadenar ningún error relacionado.

@ hill84 Interesante, pero ¿de dónde viene myRef en su ejemplo?

@Vadorequest He agregado más detalles a mi comentario anterior.

Seguir la sugerencia de @ hill84 fue una buena solución:
''
const ButtonLink: FC= ({niños, href, ... props}) => (
<

Seguir la sugerencia de @ hill84 fue una buena solución:

const ButtonLink: FC<ButtonLinkProps> = ({ children, href, ...props }) => (
  <Link href={href}>
    <><Button link {...props}>{children}</Button></>
  </Link>
);

Utilizo <><Component/></> pero Link no puede actuar. Tengo que usar <div></div> lugar de.

Sugiero una solución donde una función devuelve un objeto con accesorios en lugar de un 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>

Comprobado, funciona!

¿Por qué se necesita esta referencia? ¿Es para garantizar la ubicación correcta de href en el componente envuelto subyacente cuando se usa passHref en <Link /> ?

Esto es muy molesto ya que mi

O al menos que sea una función opcional si necesita especificar la ubicación de href en su componente. <Link href="/" passHref useRef /> ?

No creo que tener que crear otro módulo para reenviar la referencia a un componente personalizado sea una buena solución y también es demasiado repetitivo.

La forma en que estoy usando para manejar este problema es envolviendo el componente personalizado con un elemento div como lo sugiere @ namlq93, pero tampoco parece estar limpio ...

Igual que aquí. Tengo un error si uso un componente personalizado como este:

        <Link href="/href">
          <Button
            type="custom"
            color="#FCFCFC"
          >
             buttonText
          </Button>
        </Link>

Esto solo sucede cuando usa un componente cuando era niño. Estos no dan una advertencia, por ejemplo:

        <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, gracias amigo !!

Estoy teniendo un problema similar

aún allí

https://nextjs.org/docs/api-reference/next/link#if -the-child-is-a-function-component

Esto es triste.

Estaba viendo la conferencia de NextJS el otro día pensando "Wow Next es el futuro". Me gusta mucho Next y el ecosistema de Vercel y, honestamente, quiero poder decir eso y ser un defensor de Next. Sin embargo, problemas como estos que se cierran y no se abordan dificultan hacerlo. He visto este tipo de patrón varias veces a lo largo de los problemas aquí, específicamente con el enrutador.

Hay 3 soluciones a este problema desde el lado del usuario y ninguna de ellas es un gran DX.

  1. La forma recomendada de React.forwardRef. envuelva el componente en React.forwardRef . Esto puede ser muy repetitivo
  2. Envuelva el componente funcional en una etiqueta como div , span , a , etc.
  3. En lugar de Link, ingrese useRouter y use router.push

Independientemente de la solución que utilice, todas son extrañas y requieren comentarios vinculados a este problema o los documentos para explicar a los compañeros de trabajo / colaboradores por qué es necesario para evitar la eliminación / limpieza accidental.

Creo que este tema debería reabrirse para su discusión.

¿Fue útil esta página
0 / 5 - 0 calificaciones