Skip to content

Commit

Permalink
docs: update faq for infinite render question (#5451)
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinVandy authored Mar 28, 2024
1 parent 298a60b commit 3809e0a
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 0 deletions.
129 changes: 129 additions & 0 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,135 @@
title: FAQ
---

## How do I stop infinite rendering loops?

If you are using React, there is a very common pitfall that can cause infinite rendering. If you fail to give your `columns`, `data`, or `state` a stable reference, React will enter an infinite loop of re-rendering upon any change to the table state.

Why does this happen? Is this a bug in TanStack Table? **No**, it is not. *This is fundamentally how React works*, and properly managing your columns, data, and state will prevent this from happening.

TanStack Table is designed to trigger a re-render whenever either the `data` or `columns` that are passed into the table change, or whenever any of the table's state changes.

> Failing to give `columns` or `data` stable references can cause an infinite loop of re-renders.
### Pitfall 1: Creating new columns or data on every render

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

### Solution 1: Stable references with useMemo or useState

In React, you can give a "stable" reference to variables by defining them outside/above the component, or by using `useMemo` or `useState`, or by using a 3rd party state management library (like Redux or React Query 😉)

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

### Pitfall 2: Mutating columns or data in place

Even if you give your initial `columns` and `data` stable references, you can still run into infinite loops if you mutate them in place. This is a common pitfall that you may not notice that you are doing at first. Something as simple as an inline `data.filter()` can cause an infinite loop if you are not careful.

```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>;
}
```
### Solution 2: Memoize your data transformations
To prevent infinite loops, you should always memoize your data transformations. This can be done with `useMemo` or similar.
```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>;
}
```
### The Ultimate Solution: React Forget
When React Forget is released, these problems might be a thing of the past. Or use Solid.js... 🤓
## How do I stop my table state from automatically resetting when my data changes?
Most plugins use state that _should_ normally reset when the data sources changes, but sometimes you need to suppress that from happening if you are filtering your data externally, or immutably editing your data while looking at it, or simply doing anything external with your data that you don't want to trigger a piece of table state to reset automatically.
Expand Down
2 changes: 2 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,5 @@ npm install @tanstack/vue-table
```bash
npm install @tanstack/table-core
```

Don't see your favorite framework (or favorite version of your framework) listed? You can always just use the `@tanstack/table-core` package and build your own adapter in your own codebase. Usually, only a thin wrapper is needed to manage state and rendering for your specific framework. Browse the [source code](https://github.com/TanStack/table/tree/main/packages) of all of the other adapters to see how they work.

0 comments on commit 3809e0a

Please sign in to comment.