Сделайте только одну строку доступной для выбора в 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>