Сделайте только одну строку доступной для выбора в React Table 7.1.0

Я пытаюсь реализовать таблицу реагирования с возможностью выбора только одной строки за раз. Я просмотрел много примеров для выбора нескольких строк в таблице реакции, но в моем случае пользователь может выбрать только одну строку, когда пользователь нажимает переключатель, но в настоящее время могут быть выбраны все строки. Может ли кто-нибудь помочь мне реализовать это?

9 ответов

Я знаю, что это старый вопрос, но, возможно, кто-то сочтет это решение полезным. Начиная с версии 7, react-table предоставляет stateReducerкоторые можно использовать для отслеживания и изменения состояния таблицы. (до версии 7 у него было reducerHandlers, но я не углублялся в это). Вы можете изменить состояние следующим образом:

      useTable(
    {
      columns,
      data,
      stateReducer: (newState, action) => {
          if (action.type === "toggleRowSelected") {
            newState.selectedRowIds = {
              [action.id]: true
            }
          }

          return newState;
      },
    }
    ...

Вот CodeSandbox с описанными изменениями

Используя таблицу реакций 7.5.0, я собрал CodeSandbox с таблицей реакций, которая функционально позволяет выбирать только одну строку за раз.

По сути, я заменил безоговорочно отрендеренный чекбокс:

Cell: ({ row }) => (
  <div>
    <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
  </div>
)

с флажком для условного рендеринга:

Cell: ({ row }) => {
  if (
    rows.filter((row) => row.isSelected).length < 1 ||
    row.isSelected
  ) {
    return (
      <div>
        <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
      </div>
    );
  } else {
    return (
      <div>
        <IndeterminateCheckbox
          checked={false}
          readOnly
          style={row.getToggleRowSelectedProps().style}
        />
      </div>
    );
  }
}

Я отфильтровал все объекты строк, чтобы проверить выбранные строки, а затем условно отобразил нормально работающий флажок таблицы реакций, если количество выбранных строк меньше 1 или если строка уже выбрана.

Если количество проверенных строк равно по крайней мере одному, а строка не выбрана, я визуализирую флажок только для чтения, который нельзя установить.

В идеале мне хотелось бы использовать встроенный selectedRowIds в таблице реакции вместо фильтрации по всем объектам строк, но я не мог понять, как реализовать useTable() таким образом, чтобы я мог ссылаться на него, поскольку он является производным от него.

Вот песочница кода выбора строки в таблице реакции, из которой я разветвлялся. Вот соответствующая страница в их документации.

Позже я перенесу код во встроенный фрагмент кода.

      Cell: ({row}) => (
   <IndeterminateCheckbox
      {...row.getToggleRowSelectedProps({
         onChange: () => {
           const selected = row.isSelected; // get selected status of current row.
           toggleAllRowsSelected(false); // deselect all.
           row.toggleRowSelected(!selected); // reverse selected status of current row.
         },
      })}
   />
)

Для меня сработала очистка выбранных строк перед выбором новой. Версия:"@tanstack/react-table": "^8.7.4",

      Cell: ({ row, table }) => (
   <IndeterminateCheckbox
      {...row.getToggleRowSelectedProps({
         onChange: () => {
           table.resetRowSelection()
           row.toggleSelected()
         },
      })}
   />
)

Я заметил, что ответы @Ann отлично работают с небольшой проблемой - если вы хотите отключить выбранную строку, это не сработает.

Я добавил проверку, чтобы исправить это:

      useTable(
    {
      columns,
      data,
      stateReducer: (state, action) => {
         if (action.type === 'toggleRowSelected' && Object.keys(state.selectedRowIds).length) {
            const newState = { ...state };

            newState.selectedRowIds = {
              [action.id]: true,
            };

            return newState;
         }

         return state;
      },
    }
    ...
)

В TanStack Table v8 для меня проще всего было настроитьonRowSelectionChangeпараметрuseReactTable.

Я только что обновил его, чтобы сбросить локальныйrowSelectionсначала укажите пустой объект:

      const table = useReactTable({
    columns,
    data: tableData,
    state: {
        rowSelection,
    },
    enableRowSelection: true,
    onRowSelectionChange: stateUpdater => {
        setRowSelection({}); // <-- First reset the current selection
        setRowSelection(stateUpdater);
    },
    getCoreRowModel: getCoreRowModel(),
});

Вот еще песочница:

https://codesandbox.io/s/divine-shadow-9sw2xm?file=/src/App.js

Это старый, но вот мое решение:

Получить toggleAllRowsSelected из экземпляра таблицы.

        const {
    allColumns,
    getTableBodyProps,
    getTableProps,
    headerGroups,
    prepareRow,
    rows,
    state,
    toggleAllRowsSelected,
  } = useTable(
    {
      columns,
      data,
    },
    useRowSelect
  );

Затем добавьте onClick , как в приведенном ниже коде, к вашему tr -component (в моем коде tr был оформлен с эмоциями и назван StyledTableRow). Это сначала установит для всех выбранных строк значение false, а затем переключит значение isSelected для текущей строки, если оно изначально было ложным , если оно было истинным , то оно уже было установлено как ложное.

Если вы не хотите разрешать щелкать выбранную строку, чтобы отменить ее выбор (например, для переключателей), просто используйте isSelected === true , чтобы заблокировать любое действие здесь.

      {rows.map((row, i) => {
            prepareRow(row);
            // const isRowSelected = isSelected(row.id);
            const { isSelected, getRowProps, getToggleRowSelectedProps, toggleRowSelected } = row;
            const {
              onChange,
              indeterminate,
              ...toggleRowSelectedProps
            } = getToggleRowSelectedProps();
            console.log(row);
            return (
              <StyledTableRow
                hover
                {...getRowProps()}
                {...toggleRowSelectedProps}
                selected={isSelected}
                onClick={() => {
                  const current = isSelected;
                  toggleAllRowsSelected(false);
                  if (!current) {
                    toggleRowSelected();
                  }
                }}
              >
                {row.cells.map((cell, key) => (

Вы также можете переопределить метод onChange в функции prop Cell(...).

https://react-table.tanstack.com/docs/api/useRowSelect#row-properties

getToggleRowSelectedProps: Function(props) => props
Use this function to get the props needed for a select row checkbox.
Props:
onChange: Function()
style.cursor: 'pointer'
checked: Bool
title: 'Toggle Row Selected'

Отдам песочницу позже, когда будет свободное время.

Это простая реализация "радио-подобного" поведения с useReducer чтобы продемонстрировать, как использовать управление состоянием с таблицей.

const { useReducer } = React; // --> for inline use
// import React, { useReducer } from 'react';  // --> for real project


const reducer = (state, action) => {
  return { checkedId: action.id }
}

const App = () => {
  const [state, dispatch] = useReducer(reducer, {})
  
  const CheckBox = ({id}) => (
    <input
      id={id}
      onClick={() => dispatch({ id })}
      checked={state.checkedId === id}
      type="checkbox"
    />
  )

 
  return (
    <table border="1">
      <tr><td><CheckBox id="1" /></td><td>John</td></tr>
      <tr><td><CheckBox id="2" /></td><td>Doe</td></tr>
    </table>
  )
};


ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Другие вопросы по тегам