reactjs - 通过单击列标题对表格进行排序

标签 reactjs sorting html-table

我是 ReactJS 新手。我创建了一个包含 2 列的表。这是我的代码:

import React, { useState, useEffect } from 'react'
import { getUsers } from '../../services/userService'
import { useNavigate } from 'react-router-dom'
import Pagination from '@mui/material/Pagination'

const Table = () => {

    const navigate = useNavigate()

    const [users, setUsers] = useState([]);
    const [currentUsers, setCurrentUsers] = useState([]);
    const [search, setSearch] = useState('');
    const [sorting, setSorting] = useState({ key: "name", ascending: true });

    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]);


    /**************************************** */
    useEffect(() => {
        const currentUsersCopy = [...currentUsers];
    
        const sortedCurrentUsers = currentUsersCopy.sort((a, b) => {
          return a[sorting.key].localeCompare(b[sorting.key]);
        });
    
        setCurrentUsers(
          sorting.ascending ? sortedCurrentUsers : sortedCurrentUsers.reverse()
        );
    }, [currentUsers, sorting]);
    /*************************************** */

    function applySorting(key, ascending) {
        setSorting({ key: key, ascending: ascending });
    }

    /************************************** */

    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'>
            <div className='flex flex-wrap justify-between items-center'>
                <div>
                    <svg className='relative top-10 right-3' width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                        <path d="M14 5H20" stroke="#79899e" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
                        <path d="M14 8H17" stroke="#79899e" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
                        <path d="M21 11.5C21 16.75 16.75 21 11.5 21C6.25 21 2 16.75 2 11.5C2 6.25 6.25 2 11.5 2" stroke="#79899e" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
                        <path d="M22 22L20 20" stroke="#79899e" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
                    </svg>
                    <input type='text' className='my-3 py-2 pl-3 pr-10 text-sm text-text-secondary shadow-sm focus:ring-2 ring-text-secondary rounded-md w-full rd500:w-120' placeholder='search ..' onChange={(e) => setSearch(e.target.value)} value={search} />
                </div>
                
                <div className="flex justify-center">
                    <select className="form-select form-select-sm
                    my-3 py-2 pl-15 pr-2 text-sm text-text-secondary shadow-sm rounded-md w-full
                    focus:ring-2 focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none " aria-label=".form-select-sm example">
                    <option selected value="1" onClick={() => navigate('/')}>users</option>
                    <option value="2" onClick={() => navigate('/ext')}>other users</option>
                    </select>
                </div>
            </div>



            <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={() => applySorting('name', !sorting.ascending)}>name</th>
                        <th className='p-2' onClick={() => applySorting('name', !sorting.ascending)}>phone</th>
                    </tr>
                </thead>
                <tbody>
                    {currentUsers.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.name}</td>
                            <td className='text-text text-sm p-2'>{item.phone}</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

我试图通过单击每个列标题来对该表进行排序。我尝试应用 link1 中建议的解决方案和 link2 ,但我还没有成功。我怎样才能做到这一点?

已编辑:我编辑了代码并添加了表格的完整代码。

最佳答案

I'm trying to sort this table by clicking on each column header.

实现此类功能的可能解决方案之一是存储排序的当前状态。为此,我们可以使用 useState 钩子(Hook)

const [sorting, setSorting] = useState({ field: 'name', ascending: false })

如您所见,useState 函数接受默认值。在我们的例子中,默认值将是排序默认状态。 field 属性告诉我们要按哪一列进行排序,而 ascending 属性则告诉我们应该按照什么顺序排序。

接下来,我们需要为列的每个标题设置事件处理程序。

 <tr className='bg-text-secondary text-white shadow-sm text-center'>
   <th className='p-2' onClick={() => applySorting('name', !sorting.ascending)}>name</th>
   <th className='p-2' onClick={() => applySorting('phone', !sorting.ascending)}>phone</th>
 </tr>

通过单击列标题,我们调用函数 applySorting 来说明应对哪一列进行排序。

 function applySorting(key, ascending) {
   setSorting({ key: key, ascending: ascending });
 }

我们需要做的最后一件事是对存储在 currentUsers 变量中的数据进行排序。

这部分代码有点棘手,因为它使用了 useEffect 钩子(Hook)。您可以阅读React documentation了解它是如何工作的。

假设每次您更改排序变量的当前状态时,React 都会调用此函数。

  useEffect(() => {
    // Copy array to prevent data mutation
    const currentUsersCopy = [...currentUsers];

    // Apply sorting
    const sortedCurrentUsers = currentUsersCopy.sort((a, b) => {
      return a[sorting.key].localeCompare(b[sorting.key]);
    });

    // Replace currentUsers with sorted currentUsers
    setCurrentUsers(
      // Decide either currentUsers sorted by ascending or descending order
      sorting.ascending ? sortedCurrentUsers : sortedCurrentUsers.reverse()
    );
  }, [currentUsers, sorting]);

我在codesandbox上创建了这个示例,您可以在其中尝试这种方法。 Link to working example

我希望你喜欢学习 React!

关于reactjs - 通过单击列标题对表格进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72254047/

相关文章:

node.js - npm start 不适用于 Gulp js 上的 React 应用程序

node.js - 类型错误 : Cannot read property 'list' of undefined of balanceTransactions

javascript - 错误类型错误 : Cannot convert undefined or null to object

javascript - 如何使用 webpack file-loader 加载图像文件

javascript - 使用 jQuery 对重复列表中的元素进行排序

html - 具有灵活高度的表格单元格内的绝对定位

python - 如何在 Python 中对节号列表进行排序?

c++ - 按一个字段对自定义对象的 vector 进行排序

php - 如何在 PHP 中创建时间表

css - 如何将 Devexpress 主题应用到基本的 html 表格?