'fetch from api that I send requested in react-table

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;


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source