Skip to content

Instantly share code, notes, and snippets.

@DTupalov
Last active April 12, 2019 09:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DTupalov/e688a9cb640b91af52ce4bafb776366a to your computer and use it in GitHub Desktop.
Save DTupalov/e688a9cb640b91af52ce4bafb776366a to your computer and use it in GitHub Desktop.
`customCell` варианты использования
/**
* https://github.com/DTupalov/react-material-ui-datatable#reactmuidatatables-api
*
* Предполагается, что Datatable является uncontrolled component.
* Для выделения этого аспекта, принято пропы для таких компонентов именовать с приставкой `default`.
* Подробнее почитать тут: https://reactjs.org/docs/uncontrolled-components.html#default-values
*
* Необходимо понять, каким образом для `defaultColumns` использовать метод `customCell`,
* который может возвращать значение в зависимости от состояния родителя.
* Вопрос состоит в том, "можно ли" и "правильно ли" реализовать частично контролируемые и неконтролируемые значения.
* Для себя выявил, что React считает неконтролируемым только сериализуемые данные (которые можно хранить в state),
* в то время как функции вызываются те, которые передаются в момент рендера в компонент.
* Это можно проверить на классическом примере с <input defaultValue="" onChange={(e) => {}}/>, где `onChange` можно подменять
* при каждом ререндере, и он будет применяться к новому значению,
* в то время как defaultValue применяется только при инициализации компонента input.
*
* Абстрактный пример
*/
class MyPage extends React.Component {
state = {
loading: false,
data: null,
}
onDeleteEntities = async (selectedEntities) => {
this.setState({loading: true});
await axios.delete(`./api/entity`, {selectedEntities}));
this.setState({loading: false});
}
render() {
const columns = const columns = [{
name: 'a',
label: 'A',
// Кастомная ячейка, где значение - это кнопка. При выполнении запроса, кнопка должна быть неактивной,
// т.е. она зависит от родительского стейта loading
customCell: (value) => {
return <button onClick={/*move to edit page*/} disabled={this.state.loading}>{value}</button>
}
}]
return <Datatable
defaultData={data}
defaultColumns={columns}
// Панель, которая появляется при выборе элементов таблицы.
toolbarSelectActions={
(selectedEntities) => {
return <DeleteButton disabled={this.state.loading} onClick={() => this.onDeleteEntities(selectedEntities)}/>
}
}
/>
}
}
/**
* Вариант 1
* Спрятать внутри компонента логику разделения columns data (name, label etc) и columns methods (customCell, customSort etc),
* где data будет использоваться только при инициализации, а methods переданные в момент рендера.
*
* Плюсы:
* - Удобная запись с точки зрения публичного API, где видно что задекларировано в описании к колонке (данные и методы)
*
* Минусы:
* - Возможно, неочевидное поведение, когда задекларировано, что все что внутри defaultColumns
* будет использовано при инициализации, а на самом деле - нет
*/
/**
* Вариант 2
* Разделить на уровне API декларацию данных для колонки defaultColumns и customColumnsMethods
*
* Плюсы:
* - По описанию очевидно что используется только при инициализации, а что - при каждом рендере.
*
* Минусы:
* - Возможно, запись будет неудобной для чтения и полноценного понимания что происходит в конкретной колонке/ячейке
*/
/**
* Вариант 3
* Вынести рендер-функцию `customCell` вообще как отдельный prop с сигнатурой `(cellValue, column, row) => string | React.Component`
*
* Плюсы:
* - Это обычная рендер-функция, которая вызывается при каждом рендере (as controlled)
*
* Минусы:
* - Получается недекларативное описание ячейки в колонке.
* - Есть нюансы. Если захочется сделать две колонки с одинанаковым путем, в таком случае непонятно, каким образом это различать в `customCell`
*/
/**
* Вариант 4
* ???
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment