Время прочтения: 8 мин.

При работе с таблицами, как правило, требуется возможность адаптировать и настраивать различные свойства таблицы в соответствии с поставленной задачей. Среди них:

— определение видов столбцов и заговолоков

— различные форматы ячеек (текстовые, числовые, списки и т д)

— изменение размеров ячеек

— стили, шрифты, цвет текста и фона

— и другие

Для JS (JavaScrypt)  и React-приложений существует много фреймворков, один из самых популярных – это бесплатный, открытый HTML, CSS и JS фреймворк Bootstrap, который широко используется веб-разработчиками для  дизайна и вёрстки сайтов и web-приложений.

В этой статье я покажу, как работать с таблицами в React, используя специальный компонент — React Bootstrap Table, точнее, его обновленную версию — React Bootstrap Table2. На его основе можно создать достаточно сложные и красиво оформленные таблицы, затратив при этом не много усилий, и при этом настроить необходимые аспекты под свой проект. 

В примерах ниже — приложение с рабочим названием «Семейные накопления» предназначено для работы со списком вкладов, размещенных в разных банках. Оно написано  на REACT с функционалом библиотеки REDUX, но использовать компонент React Bootstrap Table2 можно и без  REDUX.

Для работы с Bootstrap необходимо добавить CSS bootstrap в файле public/index.html.

<link rel="stylesheet" 
         href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">

Для возможности использовать компонент React Bootstrap Table необходимо сначала установить пакеты с необходимыми опциями. В отличие от первой версии React Bootstrap Table2 разбит на разные пакеты по функциональности.

В нашем проекте достаточно установить 2 пакета:

Основной пакет:

npm install react-bootstrap-table-next --save

И пакет с опциями для редактирования ячеек:

npm install react-bootstrap-table2-editor --save

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

Входные данные:

export default class DataService {
data=[{
    id:1,
    owner: 'Джина',
    bank:'Сбербанк',
    currency:840,
    summa:2500,
    dataOpen:'03.06.2019',
    dataBegin:'03.06.2019',
    dataFinish:'12.06.2020',
    stavka:3.5,
    effStavka:3.5,
    comment:'ежемесячная капитализация'
},
{
    id:2,
    owner: 'Джон',
    bank:'ВТБ',
    currency:810,
    summa:100000,
    dataOpen:'02.02.2018',
    dataBegin:'02.02.2019',
    dataFinish:'08.12.2020',
    stavka:7.0,
    effStavka:7.0,
    comment:'в конце срока, без пролонгации'
}];

getData(){
    return this.data;
    }
}

В этой статье не предполагается подробного описания построение самого проекта на REACT+REDUX, поэтому приводится только состав основного файла проекта index.js, в котором используется Provider из пакета react-redux для передачи атрибута store (т.е. единого хранилища данных) всем вложенным компонентам, а также передача контекста – сервиса получения данных dataService через Provider пакета react (DataProvider). Описание структуры и пошаговое описание создания REACT +REDUX проекта Вы можете посмотреть в статье по ссылке

Основной файл index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/app';
import  {DataProvider} from './components/datastore-service-context';
import DataService from './components/services';
import {Provider} from 'react-redux';
import store from './store';

const dataService=new DataService();
ReactDOM.render( 
<Provider store={store}>
    <DataProvider value={dataService}>
         <App />
    </DataProvider> 
</Provider>,
document.getElementById('root'));

Файл основного компонента – app.js:

import VkladList from '../vklad-list-next';

const App ()=>{
    return (
        <div>
    <VkladList/>
 
    </div>);
}
export default App;

В рамках данной статьи нас будет интересовать компонент VkladList, содержащий табличные данные.

Итак, для использования таблицы react-bootstrap-table2 импортируем компонент из ранее установленного пакета, а также css-файл для таблицы:

import BootstrapTable from 'react-bootstrap-table-next';
import '../../../node_modules/react-bootstrap-table-next/dist/react-bootstrap-table2.min.css'

Для самого простого вывода данных в таблицу необходимо определить перечень столбцов — columns и передать компоненту входные данные через реквизит data. Внашем проекте мы передаем в качестве входных данных массив vklads, используя функционал библиотеки REDUX, их наш компонент VkladList получает их как props из хранилища store с помощью функции connect()  пакета react-redux. Передать входные данные можно любым другим способом через ваш сервис получения данных или даже просто объявив и заполнив массив с данными по вкладам прямо в компоненте VkladList аналогично объявлению колонок.

import React,{Component} from 'react';
import withDataService from '../hoc'
import {connect} from 'react-redux';
import { vkladloaded, vkladUpdated } from '../../actions';
import BootstrapTable from 'react-bootstrap-table-next';
import '../../../node_modules/react-bootstrap-table-next/dist/react-bootstrap-table2.min.css'
import  './vklad-list-next.css';

class VkladList extends Component { 
      componentDidMount(){
        const {dataService}=this.props;
        //Получаем данные из сервиса
        const vklads=dataService.getData();
        //передаем их в store
        this.props.vkladloaded(vklads);
    ;}
          
    render (){
      const columns=[
        {dataField:'id' ,
        text:'N'},
        {dataField:'bank',
        text:'Банк'},
  {dataField:'owner' ,
        text:'Владелец'},
        {dataField:'currency',
        text:'Валюта вклада'},
        {dataField:'summa',
        text:'Сумма'},
        {dataField:'dataOpen',
        text:'Дата Открытия'},
        {dataField:'dataFinish',
        text:'Дата Окончания'},
        {dataField:'stavka',
        text:'Ставка'},
        {dataField:'comment',
        text:'Примечания'}
      ];
         const {vklads}=this.props;
        
         return (
         <div >
         <h2 className="Table-header">Список вкладов</h2>
         <BootstrapTable data={vklads} keyField='id' columns={columns} />
      
            <div className="total">Total: $2500 P100000</div>
            
        </div>
        )
    };
};
const mapStateToProps=({vklads})=>{
    return {vklads};
        }
const mapDispatchToProps=(dispatch)=> 
{return {
    vkladloaded:(data)=>dispatch(vkladloaded(data)),
    
}
}
export default connect(mapStateToProps,mapDispatchToProps)(withDataService(VkladList));

Запускаем проект и получаем наши данные, выведенные в таблице:

Добавляем форматирование для полей дат, а в поле «Ставка» — отражение знака «%».

Для этого в описание колонок для соответствующих полей добавляем атрибут formatter, значением которого является функция форматирования. Для форматирования ставки пишем функцию прямо в строке значения, для полей дат вызываем метод нашего компонента dateFormatter.

{dataField:'dataOpen',
        text:'Дата Открытия',
        type: 'date',
        formatter: this.dateFormatter},
        {dataField:'dataFinish',
        text:'Дата Окончания',
        type: 'date',
        formatter: this.dateFormatter},
        {dataField:'stavka',
        text:'Ставка',
        type: 'number',
        formatter:(cell)=>{return `${cell}%`}},

dateFormatter:

          dateFormatter=(cell) => {
            let dateObj = cell;
            if (typeof cell !== 'object') {
              dateObj = new Date(cell);
            }
            return `${('0' + dateObj.getUTCDate()).slice(-2)}/${('0' + (dateObj.getUTCMonth() + 1)).slice(-2)}/${dateObj.getUTCFullYear()}`;
          }

Теперь нужные колонки выводятся в отформатированном виде:

Предположим, мы хотим, чтобы вклады, сроки которых подходят к концу, подсвечивались. Это сделать несложно, добавив к таблице атрибут rowClasses.  Значение этого атрибута — вызов написаного нами метода rowClass, в котором мы для нужных строк добавляем стили с использованем css:

<BootstrapTable data={vklads} keyField='id' columns={columns}
         rowClasses={this.rowClass} 
                 />

Метод rowClass для строк с нужными датами использует специальный класс ‘custom-row-class’, описанный в css-файле. Метод ValueOf()  для дат возвращает количество  миллисекунд, прошедших с полуночи 1 января 1970 до указанной даты, поэтому для определения интервала от текущей даты + 30 дней добавляем количество миллисекунд: 30*24*60*60*1000:

 rowClass = (row, rowIndex) => {
            const today=new Date();
            const dataFinish=new Date(row['dataFinish']);
            if (dataFinish.valueOf()<today.valueOf()+30*24*60*60*1000)  //окончание срока в ближайший месяц или уже закончен
              return 'custom-row-class'
              else return '';
          };

Класс ‘custom-row-class’ в нашем css файле определим следущим образом:

.custom-row-class{
  font-weight: bold;
  background-color:rgb(235, 250, 96);
}

И теперь строки, срок вклада которых завершен или скоро завершится, будут отображаться жирным шрифтом и подсвечиваться:

Добавляем возможность редактирования данных.

Это легко сделать, добавив атрибут cellEdit к таблице и определив его опции. Также надо не забыть импортировать компонент cellEditFactory из пакета react-bootstrap-table2-editor:

import cellEditFactory,{ Type } from 'react-bootstrap-table2-editor';

<BootstrapTable data={vklads} keyField='id' columns={columns}
         rowClasses={this.rowClass} 
        cellEdit={cellEditProp}
         />

В фабрике опций редактирования cellEditFactory определим несколько атрибутов:

  • mode -способ входа в режим редактирования – в нашем случае двойной щелчок мыши.
  • blurToSave  -автоматическое сохранение введенных данных при выходе из редактируемой ячейки.
  •  afterSaveCell — обработка проведенного редактирования: необходимо обновить состояние компонента, в нашем случае – обновить данные в общем хранилище, используя библиотеку redux.
const cellEditProp=cellEditFactory({
             mode:'dbclick',
             blurToSave: true,
             afterSaveCell: this.handleChange
             });

В методе handleChange проверяем, что значение ячейки действительно изменилось, и вызываем функцию vkladUpdated из actions, которая и передаст в reducer данные для внесения изменений в наш store. Для react проекта без redux в обработчике мы бы просто обновили state компонента.

handleChange=(oldValue, newValue, row, column) =>{
              if (newValue!==oldValue)
              {const newData={value:newValue,
                id:row['id'],
                field:column.dataField
                 }
                  this.props.vkladUpdated(newData);
              }     
          }

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

Например, для поля дат мы хотим, чтобы выводился календарь для выбора нужной даты. Добавляем в описание столбцов для этих полей атрибут editor:

{dataField:'dataOpen',
        text:'Дата Открытия',
        type: 'date',
        formatter: this.dateFormatter,
        editor: {
          type: Type.DATE
          }
        },
        {dataField:'dataFinish',
        text:'Дата Окончания',
        type: 'date',
        formatter: this.dateFormatter,
        editor: {
          type: Type.DATE
         }
        },

Теперь при двойном щелчке мыши на ячейке с датой предлагается календарь для выбора даты:

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

 {dataField:'currency',
        text:'Валюта вклада',
        editor:{
          type:Type.SELECT,
          options:[
            {label: "Рубли",value:810 },   
            {label: "Доллары",value:840 },
            {label: "Евро",value:978 }
            ]
          }},

Теперь при редактировании валюты появляется нужный список для выбора:

Итак, мы научились в react-проекте выводить данные в таблицу, форматировать их вывод на экран и настраивать способы редактирования для разных типов данных с помощью компонента React Bootstrap Table2. Это только небольшой перечень опций использования компонента React Bootstrap Table2. Другие его возможности рассмотрим в следующих статьях.