fetch from api that I send requested in react-table
Asked Answered
K

1

15

I will need a server-side table so after I saw react-table got 9k+ stars on github then decided to use it. I'm trying to build a React-Table which can make polling to a remote server every requested data to fetch newest data. In the example I use jsonplaceholder. requestedData func should get the data by pageSize and pageIndex (https://jsonplaceholder.typicode.com/posts?_start={pageIndex will come here}&_limit={pageSize will come here}) and return the sorted and filtered rows.

How can I do that?

Below I wrote some code:

//Table.js
import React, { useState, useEffect } from 'react';
import { useTable, useFilters, useSortBy, usePagination } from 'react-table';

export default function Table({ columns, data, pages, onFetchData, loading, pageCount: controlledPageCount, error }) {
    const [ filterInput, setFilterInput ] = useState('');
    // Use the state and functions returned from useTable to build your UI
    const {
        getTableProps,
        getTableBodyProps,
        headerGroups,
        rows,
        prepareRow,
        setFilter,
        page,
        canPreviousPage,
        canNextPage,
        pageOptions,
        pageCount,
        gotoPage,
        nextPage,
        previousPage,
        setPageSize,
        // Get the state from the instance
        state: { pageIndex, pageSize }
    } = useTable(
        //useTable is the primary hook used to build a React Table
        {
            columns,
            data,
            initialState: { pageIndex: 0 },
            manualPagination: true,
            pageCount: controlledPageCount
        },
        useFilters, //useFilters is the hook that implements row filtering
        useSortBy,
        usePagination
    );

    // Listen for changes in pagination and use the state to fetch our new data
    useEffect(
        () => {
            onFetchData({ pageIndex, pageSize });
        },
        [ onFetchData, pageIndex, pageSize ]
    );

    const handleFilterChange = (e) => {
        const value = e.target.value || undefined;
        setFilter('title', value);
        setFilterInput(value);
    };

    // Render the UI for your table
    return (
        <React.Fragment>
            <pre>
                <code>
                    {JSON.stringify(
                        {
                            pageIndex,
                            pageSize,
                            pageCount,
                            canNextPage,
                            canPreviousPage,
                            filterInput,
                            error,
                            //data,
                            onFetchData
                        },
                        null,
                        2
                    )}
                </code>
            </pre>

            <input value={filterInput} onChange={handleFilterChange} placeholder={'Search name'} />
            <table {...getTableProps()}>
                <thead>
                    {headerGroups.map((headerGroup) => (
                        <tr {...headerGroup.getHeaderGroupProps()}>
                            {headerGroup.headers.map((column) => (
                                <th
                                    {...column.getHeaderProps(column.getSortByToggleProps())}
                                    className={column.isSorted ? column.isSortedDesc ? 'sort-desc' : 'sort-asc' : ''}
                                >
                                    {column.render('Header')}
                                </th>
                            ))}
                        </tr>
                    ))}
                </thead>
                <tbody {...getTableBodyProps()}>
                    {page.map((row, i) => {
                        prepareRow(row);
                        return (
                            <tr {...row.getRowProps()}>
                                {row.cells.map((cell) => {
                                    return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>;
                                })}
                            </tr>
                        );
                    })}
                    <tr>
                        {loading ? (
                            // Use our custom loading state to show a loading indicator
                            <td colSpan='10000'>Loading...</td>
                        ) : (
                            <td colSpan='10000'>
                                Showing {page.length} of ~{controlledPageCount * pageSize} results
                            </td>
                        )}
                    </tr>
                </tbody>
            </table>
            <div className='pagination'>
                <button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
                    {'<<'}
                </button>{' '}
                <button onClick={() => previousPage()} disabled={!canPreviousPage}>
                    {'<'}
                </button>{' '}
                <button onClick={() => nextPage()} disabled={!canNextPage}>
                    {'>'}
                </button>{' '}
                <button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
                    {'>>'}
                </button>{' '}
                <span>
                    Page{' '}
                    <strong>
                        {pageIndex + 1} of {pageOptions.length}
                    </strong>{' '}
                </span>
                <span>
                    | Go to page:{' '}
                    <input
                        type='number'
                        defaultValue={pageIndex + 1}
                        onChange={(e) => {
                            const page = e.target.value ? Number(e.target.value) - 1 : 0;
                            gotoPage(page);
                        }}
                        style={{ width: '100px' }}
                    />
                </span>{' '}
                <select
                    value={pageSize}
                    onChange={(e) => {
                        setPageSize(Number(e.target.value));
                    }}
                >
                    {[ 10, 20, 30, 40, 50 ].map((pageSize) => (
                        <option key={pageSize} value={pageSize}>
                            Show {pageSize}
                        </option>
                    ))}
                </select>
            </div>
        </React.Fragment>
    );
}


//App.js
import React, { useMemo, useState, useEffect } from 'react';
import Table from './Table';
import './App.css';
import _ from 'lodash';
import axios from 'axios';

function App() {
    const columns = useMemo(
        () => [
            {
                Header: 'Information',
                columns: [
                    {
                        Header: 'Key',
                        accessor: 'id'
                    },
                    {
                        Header: 'Header',
                        accessor: 'title'
                    },
                    {
                        Header: 'Content',
                        accessor: 'body'
                    }
                ]
            }
        ],
        []
    );

    const [ data, setData ] = useState([]);
    const [ loading, setLoading ] = useState(false);
    const [ pageCount, setPageCount ] = useState(0);
    const [ error, setError ] = useState(null);

    useEffect(() => {
        (async () => {
            const result = await axios('https://jsonplaceholder.typicode.com/posts?_start=0&_limit=5');
            setData(result.data);
        })();
    }, []);

    const requestData = (pageSize, pageIndex, sorted, filtered) => {
        // Set the loading state
        setLoading(true);
        return new Promise((resolve, reject) => {
            const startRow = pageSize * pageIndex;
            axios
                .get(`https://jsonplaceholder.typicode.com/posts?_start=${startRow}&_limit=${pageSize}`)
                .then((response) => {
                    let filteredData = response.data;
                    if (filtered.length) {
                        filteredData = filtered.reduce((filteredSoFar, nextFilter) => {
                            return filteredSoFar.filter((row) => {
                                return (row[nextFilter.id] + '').includes(nextFilter.value);
                            });
                        }, filteredData);
                    }

                    const sortedData = _.orderBy(
                        filteredData,
                        sorted.map((sort) => {
                            return (row) => {
                                if (row[sort.id] === null || row[sort.id] === undefined) {
                                    return -Infinity;
                                }
                                return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id];
                            };
                        }),
                        sorted.map((d) => (d.desc ? 'desc' : 'asc'))
                    );

                    const res = {
                        rows: sortedData,
                        pages: Math.ceil(response.data.count / pageSize)
                    };

                    // setSortedData(res.rows);
                    setPageCount(res.pages);
                    setTimeout(() => resolve(res), 500);
                    setLoading(false);
                })
                .catch((error) => {
                    // setError(error);
                    console.log('error', error);
                });
        });
    };

    const fetchData = (state, instance) => {
        setLoading(true);
        requestData(state.pageSize, state.page, state.sorted, state.filtered)
            .then((res) => {
                setData(res.data);
                setPageCount(res.pages);
                setLoading(false);
            })
            .catch((err) => {
                setError(err);
                setLoading(false);
            });
    };

    return (
        <div className='App'>
            <Table
                columns={columns}
                data={data}
                pages={pageCount}
                onFetchData={fetchData}
                loading={loading}
                pageCount={pageCount}
                error={error}
            />
        </div>
    );
}

export default App;
Knavish answered 23/1, 2020 at 5:56 Comment(1)
Could you put this into a codesandbox so that we can assist better with an exampleBreda
N
0

Demo, Git Repo

Thisis the pagination properties we are providing for useReactTable.

const [{ pageIndex, pageSize }, setPagination] = useState<PaginationState>({
  pageIndex: 0,
  pageSize: 10,
});

The table it set will update the page size and page index, so we are going to listen to changes and update the table.

const [tblData, setTblData] = useState<Array<Post>>([]);
const [total, setTotal] = useState(0);

const getPageData = (page: number, size: number) => {
  fetch(
    "https://jsonplaceholder.typicode.com/posts?_start=${page}&_limit=${size}"
  )
    .then((response) => {
      console.log(response.headers.get("X-Total-Count"));
      setTotal(Number.parseInt(response.headers.get("X-Total-Count") ?? "0"));
      return response.json();
    })
    .then((json) => setTblData(json as Array<Post>));
};

useEffect(() => {
  getPageData(pageIndex, pageSize);
}, [pageIndex, pageSize]);
Nigger answered 12/12, 2023 at 17:4 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.