Next.js: Weiter 9 - Verwenden von Funktionskomponenten als untergeordnetes Element von<link/> verursacht Ref-Warnungen

Erstellt am 12. Juli 2019  ·  32Kommentare  ·  Quelle: vercel/next.js

Fehlerbericht

Beschreibe den Fehler

Die Verwendung einer Funktionskomponente als untergeordnetes Element von <Link/> verursacht:

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

Dies geschah erst nach einem Upgrade von v8 => v9.

Reproduzieren

Reproduktions-Repo: https://github.com/nickluger/nextjs-link-ref-functional-comp-warning

Erwartetes Verhalten

<Link/> sollte auch mit Funktionskomponenten funktionieren / keine Warnung anzeigen.

System Information

  • Version von Next.js: 9.0.1
bug

Hilfreichster Kommentar

Alle in einem Link manuell verpacken ? Sollte es dafür keine einfachere, weniger sich wiederholende Lösung geben? Zumindest so etwas wie <Link href="/" forwardRef>...</Link> ?

Alle 32 Kommentare

Hier gilt das gleiche. Ich habe einen Fehler Wenn ich eine benutzerdefinierte Komponente wie diese verwende:

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

Dies geschieht nur, wenn Sie eine Komponente als untergeordnetes Element verwenden. Diese geben zum Beispiel keine Warnung:

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

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

Gibt es einen Weg, um diesen Fehler zu umgehen? Wir sind für diesen Fall daran gehindert, auf 9 zu wechseln, wenn einige Funktionen, die wir wirklich nutzen möchten, wie die Typoskript-Unterstützung. Ich habe gerade bemerkt, dass es auf 9.0.3 gestoßen ist: /

Sie können versuchen, es vorübergehend stummzuschalten, z.

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

Ich habe hier das gleiche Problem.

Wenn Sie <Link/> , um Ihre benutzerdefinierte Komponente zu verpacken, können Sie ref wie folgt weiterleiten:

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

Die Warnung verschwindet.

Ich habe auf 9.0.4-canary.2 aktualisiert, erhalte aber immer noch die Warnung auf der Konsole. Vermisse ich etwas

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 Du solltest deine Komponente in React.forwardRef einschließen . Wie dieser:

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

Alle in einem Link manuell verpacken ? Sollte es dafür keine einfachere, weniger sich wiederholende Lösung geben? Zumindest so etwas wie <Link href="/" forwardRef>...</Link> ?

Stimmen Sie mit

Sollten alle anderen Bibliotheken das Attribut forwardRef auf dieselbe Weise implementieren? Oder vielleicht reagieren die Entwickler, dass Entwickler die Funktion React.forwardRef verwenden, anstatt das Attribut forwardRef implementieren?

Ja, stimme @nickluger zu , es ist Link zu tun.

Sollten wir dieses Problem erneut öffnen und umbenennen (@ijjk) oder hat jemand bereits ein neues geöffnet?

Hier gilt das gleiche. Ich habe einen Fehler Wenn ich eine benutzerdefinierte Komponente wie diese verwende:

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

Dies geschieht nur, wenn Sie eine Komponente als untergeordnetes Element verwenden. Diese geben zum Beispiel keine Warnung:

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

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

Dies wird höchstwahrscheinlich einen Konsolenfehler auslösen:

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

Ich habe dieses Problem gerade beim Upgrade von Next JS festgestellt. Gibt es eine Lösung auf dem Weg?

Ich bin nicht sicher, ob ich verstehe, wie man forwardRef verwendet und meine Komponente umschließt. Meine button.js-Datei exportiert derzeit Folgendes ....

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

export default React.memo(Button)

Siehe oben, ich habe hier ein Follow-up eröffnet: https://github.com/zeit/next.js/issues/8962

Ich habe dieses Problem gerade beim Upgrade von Next JS festgestellt. Gibt es eine Lösung auf dem Weg?

Ich bin nicht sicher, ob ich verstehe, wie man forwardRef verwendet und meine Komponente umschließt. Meine button.js-Datei exportiert derzeit Folgendes ....

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

export default React.memo(Button)

In diesem Fall sollten Sie in der Lage sein, dies einfach zu tun

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

für den forwardRef-Teil. In den Dokumenten wird auch https://nextjs.org/docs#forcing -the-link-to-expose-href-to-its-child erwähnt, obwohl ich das nicht ausprobiert habe. Ich habe das dabei gefunden

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

funktioniert (obwohl es sehr seltsam aussieht.)

Auf dieses Problem in 9.0.2 stoßen

Die Verwendung von <a></a> around funktioniert möglicherweise, löst jedoch andere Fehler aus, z. B. "muss href haben" usw., wenn a11y und ähnliches verwendet wird.

Bearbeiten: Ich habe 15 Minuten damit verbracht, dies herauszufinden. Es ist sehr langweilig, eine solche Zeitverschwendung und scheint sich trotz der Warnung richtig zu verhalten.

Persönlich ist es viel einfacher, https://github.com/zeit/next.js/issues/7915#issuecomment -511792629 zu wählen.

Was ist mit dieser Lösung ein Fragment reagieren als Lager Wrapper?

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

Wobei <MyFunctionalComponent> den Schiedsrichter weiterleitet:

import React, { forwardRef } from 'react';

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

Dies fügt der Ausgabe keinen zusätzlichen HTML-Wrapper hinzu ( <div /> ) und sollte keinen verwandten Fehler auslösen.

@ hill84 Interessant, aber woher kommt myRef in Ihrem Beispiel?

@Vadorequest Ich habe meinem vorherigen Kommentar weitere Details hinzugefügt.

Dem Vorschlag von gute Lösung :
`` `
const ButtonLink: FC= ({Kinder, href, ... Requisiten}) => (
<

Dem Vorschlag von gute Lösung :

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

Ich benutze <><Component/></> aber Link kann nicht handeln. Ich muss stattdessen <div></div> verwenden.

Ich schlage eine Lösung vor, bei der eine Funktion ein Objekt mit Requisiten anstelle einer Komponente zurückgibt:

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>

Überprüft, es funktioniert!

Warum wird dieser Schiedsrichter überhaupt benötigt? Soll die korrekte Platzierung von href in der zugrunde liegenden verpackten Komponente gewährleistet werden, wenn passHref in <Link /> ?

Dies ist sehr ärgerlich, da meine benutzerdefinierte

Oder zumindest eine Opt-In-Funktion, wenn Sie die Platzierung von href in Ihrer Komponente angeben müssen. <Link href="/" passHref useRef /> ?

Ich denke nicht, dass es eine gute Lösung ist, ein anderes Modul erstellen zu müssen, um den Ref an eine benutzerdefinierte Komponente weiterzuleiten, und es ist auch zu repetitiv.

Die Art und Weise, wie ich dieses Problem behandle , besteht darin, die benutzerdefinierte Komponente mit einem div -Element zu versehen, wie von @ namlq93 vorgeschlagen, aber es scheint auch nicht sauber zu sein ...

Hier gilt das gleiche. Ich habe einen Fehler Wenn ich eine benutzerdefinierte Komponente wie diese verwende:

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

Dies geschieht nur, wenn Sie eine Komponente als untergeordnetes Element verwenden. Diese geben zum Beispiel keine Warnung:

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

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

Es funktioniert, danke Kumpel !!

Habe ein ähnliches Problem

noch da

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

Das ist traurig.

Ich habe neulich die NextJS-Konferenz gesehen und gedacht "Wow Next ist die Zukunft". Ich mag Next und das Vercel-Ökosystem sehr und ich möchte das ehrlich sagen und ein Anwalt für Next sein können. Probleme wie diese, die geschlossen und nicht angesprochen werden, machen es jedoch schwierig, dies zu tun. Ich habe diese Art von Muster in den hier aufgeführten Problemen mehrmals gesehen, insbesondere beim Router.

Es gibt 3 Lösungen für dieses Problem von der Benutzerseite und keine von ihnen ist großartig DX.

  1. Der empfohlene Weg React.forwardRef. Wickeln Sie die Komponente in React.forwardRef . Dies kann sich sehr wiederholen
  2. Wickeln Sie die Funktionskomponente in ein Tag wie div , span , a usw. ein.
  3. Ziehen Sie anstelle von Link useRouter ein und verwenden Sie router.push

Unabhängig davon, welche Lösung Sie verwenden, sind sie alle seltsam und erfordern Kommentare, die auf dieses Problem oder die Dokumente verweisen , um Mitarbeitern / Mitwirkenden zu erklären, warum dies erforderlich ist, um ein versehentliches Entfernen / Bereinigen zu verhindern.

Ich denke, dieses Thema sollte wieder zur Diskussion gestellt werden.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen