React Table ile Tablo Oluşturma

Efenim uzatmadan direkt dalıyorum.

Not: Ben anlarım diyenler için projenin son hali buradadır.

Not 2: Test etmek isteyenleri buraya alalım.

İlk yapmanız gereken şey bir react projesi oluşturmak.

npx create-react-app datatable

Ardından hızlıca şu kurulumları aradan çıkartalım.

React table kullanmak için:

npm install react-table --save

Biraz şekil vermek için:

npm install bootstrap font-awesome@4.7 jquery popper.js  --save

Evet. Hepsi bittiyse App.js dosyamızın için şu hale getirelim.

function App() {
   return <div className="container-fluid"></div>
}

export default App 

Görüldüğü gibi tertemiz. Sadece bootstrap class ı ekledik o kadar.

Bir de anadizinde bulunan index.js dosyanıza şunları ekleyin.

import 'jquery'
import 'popper.js/dist/umd/popper'
import 'bootstrap/dist/js/bootstrap'
import 'bootstrap/dist/css/bootstrap.css'
import 'font-awesome/css/font-awesome.css'

Sonrasında src altında components adında bir dizin açalım ve içine "Datatables.css" ile "Datatable.jsx" dosyalarını oluşturalım.

Tamaaam. Temel kurulumlar bu kadar.

Alın size bir de dummy data. Buraya tıklayıp  indirebilirsiniz.

İndirdiğiniz json dosyasını da data.json olarak kaydedip anadizine atın.

Başlıyoruz.

App.js dosyasını açalım. İndirdiğimiz ve kaydettiğimiz data.json dosyasını dahil edelim.

import datalar from './data.json'

Ardından oluşturacağımız data değişkenine useMemo kullanarak bu değerleri atayalım.

const data = React.useMemo(() => {
 return datalar
}, [])

Daha sonra sütun isimlerini tekrar useMemo ile belirtelim.

  const columns = React.useMemo(
    () => [
      {
        Header: 'Ad Soyad',
        Footer: 'Ad Soyad',
        accessor: 'name', 
      },
      {
        Header: 'Profil İsmi',
        Footer: 'Profil İsmi',
        accessor: 'profil_name',
      },
      {
        Header: 'Tarih',
        Footer: 'Tarih',
        accessor: 'date',
      },
      {
        Header: 'score',
        Footer: 'score',
        accessor: 'score',
      },
      {
        Header: 'Adres',
        Footer: 'Adres',
        accessor: 'location',
      },
      {
        Header: 'Düzenle',
        accessor: (originalRow, rowIndex) => (
          <div className="d-flex  align-items-center">
            <button
              className="btn btn-warning mr-2  btn-sm"
              onClick={() => handleEdit(originalRow)}
            >
              Edit
            </button>
            <button
              className="btn btn-danger btn-sm"
              onClick={() => handleDelete(originalRow)}
            >
              Delete
            </button>
          </div>
        ),
        id: 'action',
        Footer: 'Düzenle',
      },
    ],
    [],
  )

Anlaşılacağı gibi tablo sütunlarının başlıkları "Ad Soyad, Profil İsmi, Tarih, Score, Adres ve Düzenle" olacaktır.

Buradaki accesor key'i, data.json dosyası içindeki key değerlerini gösteriyor

Düzenle kısmı için 2 adet metodumuz var. Birisi "Edit" diğeri "Delete".

Onları da oluşturuverelim.

  const handleEdit = (row) => {
    console.log(row)
  }

  const handleDelete = (row) => {
    console.log(row)
  }

Artık bu kısım size kalmış olacak haliyle. API ile iletişim kuracaksınız.

Daha sonra return kısmında da components içinde oluşturduğumuz Datatable ı çağııracağız. İçine de birkaç adet prop sıkıştıralım.

<Datatable data={data} columns={columns} tableBaslik="Personeller" />

App.js dosyamızın son hali şu şekilde olacaktır.

import './App.css'
import React from 'react'
import Datatable from './components/Datatable'

import datalar from './data.json'

function App() {
  const data = React.useMemo(() => {
    return datalar
  }, [])

  const columns = React.useMemo(
    () => [
      {
        Header: 'Ad Soyad',
        Footer: 'Ad Soyad',
        accessor: 'name', // accessor is the "key" in the data
      },
      {
        Header: 'Profil İsmi',
        Footer: 'Profil İsmi',
        accessor: 'profil_name',
      },
      {
        Header: 'Tarih',
        Footer: 'Tarih',
        accessor: 'date',
      },
      {
        Header: 'score',
        Footer: 'score',
        accessor: 'score',
      },
      {
        Header: 'Adres',
        Footer: 'Adres',
        accessor: 'location',
      },
      {
        Header: 'Düzenle',
        accessor: (originalRow, rowIndex) => (
          <div className="d-flex  align-items-center">
            <button
              className="btn btn-warning mr-2  btn-sm"
              onClick={() => handleEdit(originalRow)}
            >
              Edit
            </button>
            <button
              className="btn btn-danger btn-sm"
              onClick={() => handleDelete(originalRow)}
            >
              Delete
            </button>
          </div>
        ),
        id: 'action',
        Footer: 'Düzenle',
      },
    ],
    [],
  )

  const handleEdit = (row) => {
    console.log(row)
  }

  const handleDelete = (row) => {
    console.log(row)
  }

  return (
    <div className="container-fluid">
      <Datatable data={data} columns={columns} tableBaslik="Personeller" />
    </div>
  )
}

export default App

 

Şimdi gelelim Datatable.jsx içine..

Öncelikle yapacaklarımızı yazalım.

  1. Sıralama
  2. Sayfalama
  3. Arama ( Filtreleme )

Dolayısı ile react-table dan bunları import etmemiz gerekiyor. Tabi tablo oluşturmak için olmazsa olmaz useTable hook'umuzu da unutmuyoruz.

import {
  useTable,
  useSortBy,
  useGlobalFilter,
  useFilters,
  usePagination,
} from 'react-table'

Hemen yukarıda props olarak birkaç şey göndermiştik. Onları da çıkartıverelim.

const { data, columns, tableBaslik } = props

useTable içinden de istediğimiz property leri çıkartalım. Anlayacaksınız zaten.

const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    footerGroups,
    state,
    nextPage,
    previousPage,
    canNextPage,
    canPreviousPage,
    pageOptions,
    preGlobalFilteredRows,
    setGlobalFilter,
    page,
    prepareRow,
  } = useTable(
    {
      columns,
      data,
      initialState: {
        hiddenColumns: ['score'],
      },
    },
    useFilters,
    useGlobalFilter,
    useSortBy,
    usePagination,
)

Notlar:

  1. getTableProps: Zorunlu alandır.
  2. getTableBodyProps: Zorunlu alandır.
  3. headerGroups: Tablo header bilgisi için gerekli. <thead>
  4. footerGroups: Tablo footer bilgisi için gerekli. <tfoot>
  5. state: tablonun son halinin bilgilerini bulundurur.
  6. nextPage: Bir fonksiyondur. state.pageIndex değerini 1 arttırır.
  7. previousPage: Bir fonksiyondur. state.pageIndex değerini 1 azaltır.
  8. canNextPage: İleri giderken eğer daha sayfa var ise true döndürür. ( Bunu son sayfada ileri butonunu disabled yapmak için kullanacağız. )
  9. canPreviousPage: Geri giderken eğer 0 dan daha büyük bir sayfa var ise true döndürür. ( Bunu sayfada geri doğru giderken eğer ilk sayfada ise geri butonunu disabled yapmak için kullanacağız. )
  10. pageOptions: 0 dan başlayarak sayfa sayısını tutan bir array döndürür.
  11. page: Mevcut sayfadaki satırların olduğu bir array dir.
  12. preGlobalFilteredRows: Filtreleme işlemi yapmadan önceki tüm satırların bulunduğu bir arraydir.
  13. setGlobalFilter: state.globalFilter değerini güncellemek için kullanılır. ( Biz bu değeri ileride "GlobalFilter.jsx" adında bir dosya oluşturacağız ve orada kullanacağız.)
  14. prepareRow: Zorunlu alandır.

 

state içinden kullanağımız "pageIndex" değerini çıkartalım.

const { pageIndex } = state

 Datatable.jsx dosyamızın son hali aşağıdaki gibi olacak.

import React from 'react'
import './Datatable.css'

import {
  useTable,
  useSortBy,
  useGlobalFilter,
  useFilters,
  usePagination,
} from 'react-table'

import GlobalFilter from './GlobalFilter'

const Datatable = (props) => {
  const { data, columns, tableBaslik } = props

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    footerGroups,
    nextPage,
    previousPage,
    canNextPage,
    canPreviousPage,
    pageOptions,
    state,
    preGlobalFilteredRows,
    setGlobalFilter,
    page,

    prepareRow,
  } = useTable(
    {
      columns,
      data,
      initialState: {
        hiddenColumns: ['score'],
      },
    },
    useFilters,
    useGlobalFilter,
    useSortBy,
    usePagination,
  )

  const { pageIndex } = state

  console.log('headerGroups', headerGroups)
  //   console.log('footerGroups', footerGroups)

  return (
    <>
      <div className="row">
        <div className="col-md-12 p-3  ">
          <div className="card">
            <div className="card-header">
              <h5>
                <i className="fa fa-user" aria-hidden="true"></i> {tableBaslik}
              </h5>
            </div>
            <div className="card-body">
              <div className="globalFilterMainDiv">
                <GlobalFilter
                  preGlobalFilteredRows={preGlobalFilteredRows}
                  globalFilter={state.globalFilter}
                  setGlobalFilter={setGlobalFilter}
                />
              </div>
              <div className="table-responsive">
                <table
                  {...getTableProps()} // Tablo proplarını buradan alıyoruz.
                  className="table  table-striped table-hover"
                >
                  <thead>
                    {headerGroups.map((
                      headerGroup, // Tablo başlıklarını buradan alıyoruz.
                    ) => (
                      <tr {...headerGroup.getHeaderGroupProps()}>
                        {headerGroup.headers.map((column) => (
                          <th
                            {...column.getHeaderProps(
                              column.getSortByToggleProps, // sort edebilmek için
                            )}
                          >
                            {column.render('Header')}
                            <span>
                              {column.isSortedDesc ? ( // aşağı ve yukarı yönlü okları gösteriyoruz.
                                <i
                                  className=" fa fa-sort"
                                  aria-hidden="true"
                                ></i>
                              ) : (
                                <i
                                  className=" fa fa-sort"
                                  aria-hidden="true"
                                ></i>
                              )}
                            </span>
                          </th>
                        ))}
                      </tr>
                    ))}
                  </thead>
                  <tbody {...getTableBodyProps()}>

                    {page.map((row) => {
                      prepareRow(row)
                      return (
                        <tr {...row.getRowProps()}>
                          {row.cells.map((cell) => {
                            return (
                              <td {...cell.getCellProps()}>
                                {cell.render('Cell')}
                              </td>
                            )
                          })}
                        </tr>

                      )
                    })}
                  </tbody>

                  <tfoot>

                    {footerGroups.map((group) => (

                      <tr {...group.getFooterGroupProps()}>
                        {group.headers.map((column) => (
                          <th {...column.getFooterProps()}>
                            {column.render('Footer')}
                          </th>
                        ))}
                      </tr>

                    ))}

                  </tfoot>

                </table>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div className="row">
        <div className="col-md-12">
          <div className="dataTable-pagination d-flex justify-content-end">
            <span className="pageOptionsSpan">
              {' '}
              {pageIndex + 1} / {pageOptions.length}{' '}
            </span>
            <button
              className="btn btn-primary btn-sm mr-2"
              onClick={() => previousPage()}
              disabled={!canPreviousPage}
            >
              <i className="fa fa-chevron-left" aria-hidden="true"></i>
            </button>

            <button
              className="btn btn-primary btn-sm"
              onClick={() => nextPage()}
              disabled={!canNextPage}
            >
              <i className="fa fa-chevron-right" aria-hidden="true"></i>
            </button>
          </div>
        </div>
      </div>
    </>
  )
}

export default Datatable

 

Son olarak GlobalFilter.jsx dosyamızı da şuraya ekleyelim.

import React from 'react'
import { useAsyncDebounce } from 'react-table'

const GlobalFilter = ({
  preGlobalFilteredRows,
  globalFilter,
  setGlobalFilter,
}) => {
  const count = preGlobalFilteredRows.length

  const [value, setValue] = React.useState(globalFilter)
  const onChange = useAsyncDebounce((value) => {
    setGlobalFilter(value || undefined)
  }, 200)

  return (
    <div className="mb-3 row">
      <label htmlFor="globalFilterInput" className="col-sm-1 col-form-label">
        Ara:
      </label>

      <div className="col-sm-11">
        <input
          className="form-control"
          id="globalFilterInput"
          value={value || ''}
          onChange={(e) => {
            setValue(e.target.value)
            setGlobalFilter(e.target.value || undefined)
          }}
          placeholder={`${count} kayıt içinde arama yap...`}
        />
      </div>
    </div>
  )
}

export default GlobalFilter

Tahmin edeceğiniz üzere arama inputumuzun çalışmasını burada gerçekleştiriyoruz.

Son halinin görseli aşağıdaki gibi olacaktır.

 

Yazarken çok sıkıldım. Atladığım yerler zorunlu olarak kütüphaneden gelen değerlerdir.

Neyse hepsi bu kadar..

Bir kenarda dursun..

 

 

 

 

 

2303 Görüntülenme

Yorum Yap