Table State (Angular) 指南

Table State (Angular) 指南

TanStack Table 有一个简单的底层内部状态管理系统,用于存储和管理表格的状态。它还允许您选择性地提取任何需要由您自己的状态管理系统来管理的状态。本指南将引导您了解可以与表格状态进行交互和管理它的不同方法。

访问表格状态

您无需进行任何特殊的设置即可使表格状态正常工作。如果您没有在 stateinitialState 或任何 on[State]Change 表格选项中传入任何值,表格将内部管理自己的状态。您可以使用 table.getState() 表格实例 API 来访问此内部状态的任何部分。

ts
table = createAngularTable(() => ({
  columns: this.columns,
  data: this.data(),
  //...
}))

someHandler() {
  console.log(this.table.getState()) //access the entire internal state
  console.log(this.table.getState().rowSelection) //access just the row selection state
}
table = createAngularTable(() => ({
  columns: this.columns,
  data: this.data(),
  //...
}))

someHandler() {
  console.log(this.table.getState()) //access the entire internal state
  console.log(this.table.getState().rowSelection) //access just the row selection state
}

自定义初始状态

如果只需要为某些状态自定义其初始默认值,仍然不需要自己管理任何状态。您只需在表格实例的 initialState 选项中设置值即可。

jsx
table = createAngularTable(() => ({
  columns: this.columns,
  data: this.data(),
  initialState: {
    columnOrder: ['age', 'firstName', 'lastName'], //customize the initial column order
    columnVisibility: {
      id: false //hide the id column by default
    },
    expanded: true, //expand all rows by default
    sorting: [
      {
        id: 'age',
        desc: true //sort by age in descending order by default
      }
    ]
  },
  //...
}))
table = createAngularTable(() => ({
  columns: this.columns,
  data: this.data(),
  initialState: {
    columnOrder: ['age', 'firstName', 'lastName'], //customize the initial column order
    columnVisibility: {
      id: false //hide the id column by default
    },
    expanded: true, //expand all rows by default
    sorting: [
      {
        id: 'age',
        desc: true //sort by age in descending order by default
      }
    ]
  },
  //...
}))

注意:对于每个特定状态,只在 initialStatestate 中指定,而不是两者都指定。如果您将某个特定状态值同时传递给 initialStatestate,则 state 中的初始化状态将覆盖 initialState 中的任何相应值。

受控状态

如果您需要在应用程序的其他区域轻松访问表格状态,TanStack Table 可以轻松地在您自己的状态管理系统中控制和管理任何或所有表格状态。您可以通过将自己的状态和状态管理函数传递给 stateon[State]Change 表格选项来完成此操作。

独立受控状态

您可以只控制您需要轻松访问的状态。如果您不需要,则不必控制所有表格状态。建议仅根据具体情况控制所需的状态。

为了控制某个特定状态,您需要同时将相应的 state 值和 on[State]Change 函数传递给表格实例。

以“手动”服务器端数据获取场景中的过滤、排序和分页为例。您可以将过滤、排序和分页状态存储在自己的状态管理系统中,但如果您的 API 不关心这些值,则可以省略列顺序、列可见性等其他状态。

ts
import {signal} from '@angular/core';
import {SortingState, ColumnFiltersState, PaginationState} from '@tanstack/angular-table'
import {toObservable} from "@angular/core/rxjs-interop";
import {combineLatest, switchMap} from 'rxjs';

class TableComponent {
  readonly columnFilters = signal<ColumnFiltersState>([]) //no default filters
  readonly sorting = signal<SortingState>([
    {
      id: 'age',
      desc: true, //sort by age in descending order by default
    }
  ])
  readonly pagination = signal<PaginationState>({
    pageIndex: 0,
    pageSize: 15
  })

  //Use our controlled state values to fetch data
  readonly data$ = combineLatest({
    filters: toObservable(this.columnFilters),
    sorting: toObservable(this.sorting),
    pagination: toObservable(this.pagination)
  }).pipe(
    switchMap(({filters, sorting, pagination}) => fetchData(filters, sorting, pagination))
  )
  readonly data = toSignal(this.data$);

  readonly table = createAngularTable(() => ({
    columns: this.columns,
    data: this.data(),
    //...
    state: {
      columnFilters: this.columnFilters(), //pass controlled state back to the table (overrides internal state)
      sorting: this.sorting(),
      pagination: this.pagination(),
    },
    onColumnFiltersChange: updater => { //hoist columnFilters state into our own state management
      updater instanceof Function
        ? this.columnFilters.update(updater)
        : this.columnFilters.set(updater)
    },
    onSortingChange: updater => {
      updater instanceof Function
        ? this.sorting.update(updater)
        : this.sorting.set(updater)
    },
    onPaginationChange: updater => {
      updater instanceof Function
        ? this.pagination.update(updater)
        : this.pagination.set(updater)
    },
  }))
}

//...
import {signal} from '@angular/core';
import {SortingState, ColumnFiltersState, PaginationState} from '@tanstack/angular-table'
import {toObservable} from "@angular/core/rxjs-interop";
import {combineLatest, switchMap} from 'rxjs';

class TableComponent {
  readonly columnFilters = signal<ColumnFiltersState>([]) //no default filters
  readonly sorting = signal<SortingState>([
    {
      id: 'age',
      desc: true, //sort by age in descending order by default
    }
  ])
  readonly pagination = signal<PaginationState>({
    pageIndex: 0,
    pageSize: 15
  })

  //Use our controlled state values to fetch data
  readonly data$ = combineLatest({
    filters: toObservable(this.columnFilters),
    sorting: toObservable(this.sorting),
    pagination: toObservable(this.pagination)
  }).pipe(
    switchMap(({filters, sorting, pagination}) => fetchData(filters, sorting, pagination))
  )
  readonly data = toSignal(this.data$);

  readonly table = createAngularTable(() => ({
    columns: this.columns,
    data: this.data(),
    //...
    state: {
      columnFilters: this.columnFilters(), //pass controlled state back to the table (overrides internal state)
      sorting: this.sorting(),
      pagination: this.pagination(),
    },
    onColumnFiltersChange: updater => { //hoist columnFilters state into our own state management
      updater instanceof Function
        ? this.columnFilters.update(updater)
        : this.columnFilters.set(updater)
    },
    onSortingChange: updater => {
      updater instanceof Function
        ? this.sorting.update(updater)
        : this.sorting.set(updater)
    },
    onPaginationChange: updater => {
      updater instanceof Function
        ? this.pagination.update(updater)
        : this.pagination.set(updater)
    },
  }))
}

//...

完全受控状态

或者,您可以使用 onStateChange 表格选项来控制整个表格状态。它会将整个表格状态提升到您的状态管理系统中。请注意这种方法,因为您可能会发现将一些频繁更改的状态值(如 columnSizingInfo 状态)提升到组件树的更高层可能会导致性能问题。

可能需要一些额外的技巧才能使其正常工作。如果您使用 onStateChange 表格选项,则 state 的初始值必须包含您要使用的所有功能的全部相关状态值。您可以手动输入所有初始状态值,或者如下所示以特殊方式使用构造函数。

ts


class TableComponent {
  // create an empty table state, we'll override it later
  readonly state = signal({} as TableState);

  // create a table instance with default state values
  readonly table = createAngularTable(() => ({
    columns: this.columns,
    data: this.data(),
    // our fully controlled state overrides the internal state
    state: this.state(),
    onStateChange: updater => {
      // any state changes will be pushed up to our own state management
      this.state.set(
        updater instanceof Function ? updater(this.state()) : updater
      )
    }
  }))

  constructor() {
    // set the initial table state
    this.state.set({
      // populate the initial state with all of the default state values
      // from the table instance
      ...this.table.initialState,
      pagination: {
        pageIndex: 0,
        pageSize: 15, // optionally customize the initial pagination state.
      },
    })
  }
}


class TableComponent {
  // create an empty table state, we'll override it later
  readonly state = signal({} as TableState);

  // create a table instance with default state values
  readonly table = createAngularTable(() => ({
    columns: this.columns,
    data: this.data(),
    // our fully controlled state overrides the internal state
    state: this.state(),
    onStateChange: updater => {
      // any state changes will be pushed up to our own state management
      this.state.set(
        updater instanceof Function ? updater(this.state()) : updater
      )
    }
  }))

  constructor() {
    // set the initial table state
    this.state.set({
      // populate the initial state with all of the default state values
      // from the table instance
      ...this.table.initialState,
      pagination: {
        pageIndex: 0,
        pageSize: 15, // optionally customize the initial pagination state.
      },
    })
  }
}

状态变更回调

到目前为止,我们已经看到了 on[State]ChangeonStateChange 表格选项如何将表格状态更改“提升”到我们自己的状态管理中。但是,在使用这些选项时,有几点您应该注意。

1. 状态变更回调必须在其 state 选项中包含相应的状态值

指定 on[State]Change 回调函数会告诉表格实例这是一个受控状态。如果您没有指定相应的 state 值,该状态将以其初始值“冻结”。

ts
class TableComponent {
  sorting = signal<SortingState>([])

  table = createAngularTable(() => ({
    columns: this.columns,
    data: this.data(),
    //...
    state: {
      sorting: this.sorting(), // required because we are using `onSortingChange`
    },
    onSortingChange: updater => { // makes the `state.sorting` controlled
      updater instanceof Function
        ? this.sorting.update(updater)
        : this.sorting.set(updater)
    }
  }))
}
class TableComponent {
  sorting = signal<SortingState>([])

  table = createAngularTable(() => ({
    columns: this.columns,
    data: this.data(),
    //...
    state: {
      sorting: this.sorting(), // required because we are using `onSortingChange`
    },
    onSortingChange: updater => { // makes the `state.sorting` controlled
      updater instanceof Function
        ? this.sorting.update(updater)
        : this.sorting.set(updater)
    }
  }))
}

2. 更新器可以是原始值,也可以是回调函数

on[State]ChangeonStateChange 回调函数的工作方式与 React 中的 setState 函数完全相同。更新值可以是新的状态值,也可以是接受前一个状态值并返回新状态值的回调函数。

这有什么影响?这意味着,如果您想在任何 on[State]Change 回调函数中添加一些额外的逻辑,您可以这样做,但您需要检查新的传入更新值是函数还是值。

这就是为什么您会在上面的示例中看到 updater instanceof Function ? this.state.update(updater) : this.state.set(updater) 模式。此模式会检查更新值是否为函数,如果是,则使用前一个状态值调用该函数以获取新状态值,或者信号将要求使用 signal.update 代替 signal.set 调用更新值。

状态类型

TanStack Table 中的所有复杂状态都有自己的 TypeScript 类型,您可以导入并使用它们。这对于确保您正在为要控制的状态值使用正确的数据结构和属性非常有用。

ts
import {createAngularTable, type SortingState} from '@tanstack/angular-table'

class TableComponent {
  readonly sorting = signal<SortingState>([
    {
      id: 'age', // you should get autocomplete for the `id` and `desc` properties
      desc: true,
    }
  ])
}
import {createAngularTable, type SortingState} from '@tanstack/angular-table'

class TableComponent {
  readonly sorting = signal<SortingState>([
    {
      id: 'age', // you should get autocomplete for the `id` and `desc` properties
      desc: true,
    }
  ])
}
我们的合作伙伴
Code Rabbit
AG Grid
订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。

订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。