Home > OS >  Apply sorting on all table users instead of the users of a single page
Apply sorting on all table users instead of the users of a single page

Time:05-30

I have a table with 2 columns containing users info. I have divided the the table users in multiple pages, so that table of each page only displays 15 users. I have also implemented sorting on this table, so that when I click on each column header, the table is sorted according to this column. Here is the code:

import React, { useState, useEffect } from 'react'
import { getUsers } from '../../services/userService'

const Table = () => {

const [users, setUsers] = useState([]);
const [currentUsers, setCurrentUsers] = useState([]);
const [search, setSearch] = useState('');
const [isSorted, setIsSorted] = useState(false);
const [valueHeader, setValueHeader] = useState({title: "",body: ""}); //Value header state
const [sortedUsers, setSortedUsers] = useState([]);


const pageItemCount = 15
const [pageCount, setPageCount] = useState(0)
const [currentPage, setCurrentPage] = useState(1)

useEffect(async () => {
    try {
        const response = await getUsers(search);
        setUsers(response.data.users);
        setPageCount(Math.ceil(response.data.users.length / pageItemCount))
        setCurrentUsers(response.data.users.slice(0, pageItemCount))
    } catch (error) { }
}, [search]);

const sortFn = (userA, userB) => {
  // sort logic here, it can be whatever is needed
  // sorting alphabetically by `first_name` in this case
  return userA[valueHeader.body].localeCompare(userB[valueHeader.body]) //<== Use value of culumn header
}

useEffect(() => {
    if (isSorted) {
      setSortedUsers(currentUsers.slice().sort(sortFn))
    } else {
      setSortedUsers(currentUsers)
    }
  }, [isSorted, currentUsers, valueHeader]) //<== add valueHeader to dependency

const toggleSort = (target) => {
  setIsSorted(!isSorted)
  setValueHeader({
    title: target,
    body: target == "name" ? "first_name" : "mobile_number"
  }) //<=== set state of value header
}

const changePage = (i) => {
    setCurrentPage(i)
    const startItem = ((i - 1) * pageItemCount)   1
    setCurrentUsers(users.slice(startItem - 1, (pageItemCount * i)))
}

const handleChange = (event, value) => {
    changePage(value);
}

    return (
        <div dir='rtl' className='bg-background mt-10 px-5 rd1200:px-30 overflow-auto'>
           
            <table className='w-full border-separate rounded-md'>
                <thead>
                    <tr className='bg-text-secondary text-white shadow-sm text-center'>
                        <th className='p-2' onClick={()=>toggleSort("name")}>name</th>
                        <th className='p-2' onClick={()=>toggleSort("mobile")}>mobile</th>
                    </tr>
                </thead>
                <tbody>
                    {sortedUsers.map((item, index) =>
                        <tr key={item.id} className={index % 2 === 0 ? 'bg-white shadow-sm text-center' : 'bg-text bg-opacity-5 shadow-sm text-center'}>
                            <td className='text-text text-sm p-2'>{item.first_name}</td>
                            <td className='text-text text-sm p-2'>{item.mobile_number}</td> 
                        </tr>
                    )}
                </tbody>
            </table>
            <Pagination className="mt-2 pb-20" dir='ltr' page={currentPage} count={pageCount} onChange={handleChange} variant="outlined" shape="rounded" />                
        </div>
    )
}

export default Table

The only problem is that, since I display only 15 users of the table in each page, when I click on the column header, only the users of that page is sorted, but I want to apply sorting on all users of the table (the users of all pages). Is it possible?

CodePudding user response:

You have 2 methods the first is sorting the users array but this will change the users in this page The second is wich i prefere is to call the sorting function in the changepage function

CodePudding user response:

The error it's in this useEffect logic:

useEffect(() => {
    if (isSorted) {
      // When its sorted, you are setting to sort currentUsers,
      // and it holds only the first 15 users, not the entire users array
      setSortedUsers(currentUsers.slice().sort(sortFn))
    } else {
      setSortedUsers(currentUsers)
    }
  }, [isSorted, currentUsers, valueHeader]) 

The below code should work for you:

useEffect(() => {
    if (isSorted) {

      // get all users and sort it, 
      // returning an immutable array because the use of .slice()
      const usersUpdated = users.slice().sort(sortFn).slice(0, pageItemCount);

      // Updated the currentUsers and sortedUsers states
      setSortedUsers(usersUpdated);
      setCurrentUsers(usersUpdated);
    } else {
      // Updated the currentUsers and sortedUsers states with the first 15 users
      setSortedUsers(users.slice(0, pageItemCount));
      setCurrentUsers(users.slice(0, pageItemCount));
    }
  // instead call the useEffect base on currentUsers, you change it to users
  }, [isSorted, users, valueHeader]);

Having said that, just a point - You are using to many states for user:
. one for all users
. one for current users
. one for sorted users

You can handle this with only one state, i did a code sample to you check it.

  • Related