Framework
Version
Enterprise

FAQ

Wie stoppe ich Endlosschleifen beim Rendern?

Wenn Sie React verwenden, gibt es einen sehr häufigen Fallstrick, der zu unendlichen Renderings führen kann. Wenn Sie Ihren Spalten, Daten oder Zustand keine stabile Referenz geben, gerät React bei jeder Änderung des Tabellenzustands in eine Endlosschleife beim Rendern.

Warum passiert das? Ist das ein Fehler in TanStack Table? Nein, das ist es nicht. Das ist die grundlegende Funktionsweise von React, und die ordnungsgemäße Verwaltung Ihrer Spalten, Daten und Ihres Zustands verhindert, dass dies geschieht.

TanStack Table ist so konzipiert, dass ein erneutes Rendern ausgelöst wird, wann immer sich die übergebenen Daten oder Spalten ändern oder wann immer sich ein Teil des Tabellenzustands ändert.

Wenn Sie Ihren Spalten oder Daten keine stabilen Referenzen geben, kann dies zu einer Endlosschleife beim erneuten Rendern führen.

Fallstrick 1: Bei jedem Rendern neue Spalten oder Daten erstellen

js
export default function MyComponent() {
  //😵 BAD: This will cause an infinite loop of re-renders because `columns` is redefined as a new array on every render!
  const columns = [
    // ...
  ];

  //😵 BAD: This will cause an infinite loop of re-renders because `data` is redefined as a new array on every render!
  const data = [
    // ...
  ];

  //❌ Columns and data are defined in the same scope as `useReactTable` without a stable reference, will cause infinite loop!
  const table = useReactTable({
    columns,
    data,
  });

  return <table>...</table>;
}
export default function MyComponent() {
  //😵 BAD: This will cause an infinite loop of re-renders because `columns` is redefined as a new array on every render!
  const columns = [
    // ...
  ];

  //😵 BAD: This will cause an infinite loop of re-renders because `data` is redefined as a new array on every render!
  const data = [
    // ...
  ];

  //❌ Columns and data are defined in the same scope as `useReactTable` without a stable reference, will cause infinite loop!
  const table = useReactTable({
    columns,
    data,
  });

  return <table>...</table>;
}

Lösung 1: Stabile Referenzen mit useMemo oder useState

In React können Sie Variablen eine "stabile" Referenz geben, indem Sie sie außerhalb/oberhalb der Komponente definieren oder indem Sie useMemo oder useState verwenden oder eine Drittanbieter-Zustandsverwaltung (wie Redux oder React Query 😉) verwenden.

js
//✅ OK: Define columns outside of the component
const columns = [
  // ...
];

//✅ OK: Define data outside of the component
const data = [
  // ...
];

// Usually it's more practical to define columns and data inside the component, so use `useMemo` or `useState` to give them stable references
export default function MyComponent() {
  //✅ GOOD: This will not cause an infinite loop of re-renders because `columns` is a stable reference
  const columns = useMemo(() => [
    // ...
  ], []);

  //✅ GOOD: This will not cause an infinite loop of re-renders because `data` is a stable reference
  const [data, setData] = useState(() => [
    // ...
  ]);

  // Columns and data are defined in a stable reference, will not cause infinite loop!
  const table = useReactTable({
    columns,
    data,
  });

  return <table>...</table>;
}
//✅ OK: Define columns outside of the component
const columns = [
  // ...
];

//✅ OK: Define data outside of the component
const data = [
  // ...
];

// Usually it's more practical to define columns and data inside the component, so use `useMemo` or `useState` to give them stable references
export default function MyComponent() {
  //✅ GOOD: This will not cause an infinite loop of re-renders because `columns` is a stable reference
  const columns = useMemo(() => [
    // ...
  ], []);

  //✅ GOOD: This will not cause an infinite loop of re-renders because `data` is a stable reference
  const [data, setData] = useState(() => [
    // ...
  ]);

  // Columns and data are defined in a stable reference, will not cause infinite loop!
  const table = useReactTable({
    columns,
    data,
  });

  return <table>...</table>;
}

Fallstrick 2: Spalten oder Daten vor Ort mutieren

Selbst wenn Sie Ihren ursprünglichen Spalten und Daten stabile Referenzen geben, können Sie immer noch in Endlosschleifen geraten, wenn Sie sie vor Ort mutieren. Dies ist ein häufiger Fallstrick, bei dem Sie vielleicht nicht sofort bemerken, dass Sie ihn tun. Etwas so Einfaches wie ein Inline-data.filter() kann zu einer Endlosschleife führen, wenn Sie nicht vorsichtig sind.

js
export default function MyComponent() {
  //✅ GOOD
  const columns = useMemo(() => [
    // ...
  ], []);

  //✅ GOOD (React Query provides stable references to data automatically)
  const { data, isLoading } = useQuery({
    //...
  });

  const table = useReactTable({
    columns,
    //❌ BAD: This will cause an infinite loop of re-renders because `data` is mutated in place (destroys stable reference)
    data: data?.filter(d => d.isActive) ?? [],
  });

  return <table>...</table>;
}
export default function MyComponent() {
  //✅ GOOD
  const columns = useMemo(() => [
    // ...
  ], []);

  //✅ GOOD (React Query provides stable references to data automatically)
  const { data, isLoading } = useQuery({
    //...
  });

  const table = useReactTable({
    columns,
    //❌ BAD: This will cause an infinite loop of re-renders because `data` is mutated in place (destroys stable reference)
    data: data?.filter(d => d.isActive) ?? [],
  });

  return <table>...</table>;
}

Lösung 2: Memoize deine Datentransformationen

Um Endlosschleifen zu verhindern, sollten Sie Ihre Datentransformationen immer memoizen. Dies kann mit useMemo oder Ähnlichem erfolgen.

js
export default function MyComponent() {
  //✅ GOOD
  const columns = useMemo(() => [
    // ...
  ], []);

  //✅ GOOD
  const { data, isLoading } = useQuery({
    //...
  });

  //✅ GOOD: This will not cause an infinite loop of re-renders because `filteredData` is memoized
  const filteredData = useMemo(() => data?.filter(d => d.isActive) ?? [], [data]);

  const table = useReactTable({
    columns,
    data: filteredData, // stable reference!
  });

  return <table>...</table>;
}
export default function MyComponent() {
  //✅ GOOD
  const columns = useMemo(() => [
    // ...
  ], []);

  //✅ GOOD
  const { data, isLoading } = useQuery({
    //...
  });

  //✅ GOOD: This will not cause an infinite loop of re-renders because `filteredData` is memoized
  const filteredData = useMemo(() => data?.filter(d => d.isActive) ?? [], [data]);

  const table = useReactTable({
    columns,
    data: filteredData, // stable reference!
  });

  return <table>...</table>;
}

React Forget

Wenn React Forget veröffentlicht wird, könnten diese Probleme der Vergangenheit angehören. Oder verwenden Sie einfach Solid.js... 🤓

Wie verhindere ich, dass der Tabellenzustand beim Ändern meiner Daten automatisch zurückgesetzt wird?

Die meisten Plugins verwenden einen Zustand, der sich normalerweise zurücksetzen sollte, wenn sich die Datenquelle ändert, aber manchmal müssen Sie dies verhindern, wenn Sie Ihre Daten extern filtern, Ihre Daten unveränderlich bearbeiten, während Sie sie betrachten, oder einfach etwas Externes mit Ihren Daten tun, das nicht dazu führen soll, dass ein Teil des Tabellenzustands automatisch zurückgesetzt wird.

Für diese Fälle bietet jedes Plugin eine Möglichkeit, den automatischen Rücksetzvorgang des Zustands zu deaktivieren, wenn sich Daten oder andere Abhängigkeiten eines Zustandsteils ändern. Indem Sie einen davon auf false setzen, können Sie die automatischen Rücksetzungen verhindern.

Hier ist ein auf React basierendes Beispiel, um im Grunde alle Zustandsänderungen zu stoppen, die normalerweise auftreten, während wir die Datenquelle einer Tabelle bearbeiten

js
const [data, setData] = React.useState([])
const skipPageResetRef = React.useRef()

const updateData = newData => {
  // When data gets updated with this function, set a flag
  // to disable all of the auto resetting
  skipPageResetRef.current = true

  setData(newData)
}

React.useEffect(() => {
  // After the table has updated, always remove the flag
  skipPageResetRef.current = false
})

useReactTable({
  ...
  autoResetPageIndex: !skipPageResetRef.current,
  autoResetExpanded: !skipPageResetRef.current,
})
const [data, setData] = React.useState([])
const skipPageResetRef = React.useRef()

const updateData = newData => {
  // When data gets updated with this function, set a flag
  // to disable all of the auto resetting
  skipPageResetRef.current = true

  setData(newData)
}

React.useEffect(() => {
  // After the table has updated, always remove the flag
  skipPageResetRef.current = false
})

useReactTable({
  ...
  autoResetPageIndex: !skipPageResetRef.current,
  autoResetExpanded: !skipPageResetRef.current,
})

Wenn wir nun unsere Daten aktualisieren, werden die oben genannten Tabellen-Zustände nicht automatisch zurückgesetzt!

Unsere Partner
Code Rabbit
AG Grid
Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.

Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.