How to initially auto-expand all rows with react-table 7?
Asked Answered
L

2

6

I'm looking for an easy and clean way to make all rows to be auto-expanded when using react-table v7.

When I map all the data to true and set it as an initial state, it does not expand my rows.

const expanded = {
  1: true,
  2: true,
  ...
};

...

useTable(
  {
    ...
    initialState: {
      expanded
    }
  }
);

By dumping table state expanded prop, I've found out there are generated non-numeric keys like {Col1:somevalue2: true} (grouped columns). I don't have an access to those keys before table instance is created and therefore I also don't have an access to row ids in order to generate initial state.

The only way I've found is below but I'd prefer the tableInstance to be expanded initially (as a result of useTable() hook).

React.useEffect(() => tableInstance.toggleAllRowsExpanded(true), []);

Relevant Github FR discussion: https://github.com/tannerlinsley/react-table/discussions/3317

Lame answered 7/6, 2021 at 17:36 Comment(1)
thanks, in my case i was implementing a "expand all" button so your solution was ideal!Bidentate
S
2

Like you mentioned, using toggleAllRowsExpanded(true) is going to be the easiest way to expand all of the rows. However, if you want this to happen within useTable, you can write a custom plugin hook which runs this logic in the useInstance hook based on a new initialState.startExpanded boolean.

// useStartExpanded.tsx
import { useEffect } from 'react'
import { Hooks, TableInstance } from 'react-table'

export interface UseStartExpandedState<D extends object> {
  startExpanded: boolean
}

export const useStartExpanded = <D extends object = {}>(hooks: Hooks<D>): void => {
  hooks.useInstance.push(useInstance)
}
useStartExpanded.pluginName = 'useStartExpanded'

const useInstance = <D extends object = {}>(instance: TableInstance<D>): void => {
  const {
    state: { startExpanded },
    toggleAllRowsExpanded
  } = instance

  useEffect(() => {
    if (startExpanded) toggleAllRowsExpanded(true)
  }, [startExpanded, toggleAllRowsExpanded])
}

Usage would look something like this:

// MyTable.tsx
import { useMemo } from 'react'
import { Column, useExpanded, useGroupBy, useTable } from 'react-table'
import { useStartExpanded } from './useStartExpanded'

export type Data = { id: string }

export const MyTable = ({ startExpanded = true }) => {
  const data: Data[] = useMemo(() => [], [])
  const columns: Column<Data>[] = useMemo(() => [], [])

  const tableInstance = useTable<Data>(
    { columns, data, initialState: { startExpanded } },
    useGroupBy,
    useExpanded,
    useStartExpanded
  )

  return <>...</>
}

Since this example is in TypeScript, you'll need to add the startExpanded to the TableState type definition.

// react-table-config.d.ts
import { UseExpandedState, UseGroupByState } from 'react-table'
import { UseStartExpandedState } from './useStartExpanded'

declare module 'react-table' {
  export interface TableState<D extends object = {}>
    extends UseExpandedState<D>,
      UseGroupByState<D>,
      UseStartExpandedState<D> {}
}
Social answered 7/4, 2022 at 19:5 Comment(0)
I
0

What you wrote makes intuitive sense based off of what the documentation says, but is missing a key element. You have to tell initialState that your "expanded" object is tied to the "expanded" property, like this:

  const initialExpanded = React.useMemo(() => {
    return {
      "expanded": {
        "0": true,
        "4": true
      }
  }}, [])
  const { /* ... */ } = useTable({
    initialState: { initialExpanded }, 
    /* etc */
  });
Infanticide answered 28/6, 2021 at 0:40 Comment(5)
I don't see how is it different from my example and also how does it expand grouped rows?Lame
@Lame Your object is missing the "expanded" part. { "1": true } vs { "expanded": { "1": true } } basically. As for grouped rows, you have to include them explicitly -- so, you need "1" and also "1.1" and "1.2" etcInfanticide
the expanded part is right there: initialState: { expanded }. And the point is I really don't know ids of grouped rows and don't want to create an algorithm to find them. I'd expect react-table to have one already and do it for me.Lame
My apologies, I totally missed that part of your answer apparently? Anyway, if you can't pre-generate IDs based on your data, then I don't know of any method or object that react-table exposes that allows you to pre-set all rows to be toggled. I think you're already using the optimal solution: hooks. It's a fairly elegant solution, unless there's render-time lag or something, I guess.Infanticide
Yup. unfortunately, it's kind of dirty workaround. Table blinks and it is not optimal in terms of rerender count. As you said, it seems there's no proper way so far. Thanks anyway.Lame

© 2022 - 2024 — McMap. All rights reserved.