Home > Software design >  The clicked column header cannot be determined correctly
The clicked column header cannot be determined correctly

Time:05-22

I'm new to ReactJS. I have a table with 2 columns. I want to sort the table based on the column header that is clicked on. 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 [isSorted, setIsSorted] = useState(false);
    const [valueHeader, setValueHeader] = useState({title: "",body: ""}); //Value header state
    const [sortedUsers, setSortedUsers] = useState([]);


    useEffect(async () => {
    try {
        const response = await getUsers(search);
        setUsers(response.data.users);
    } 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.value,
    body: target.value == "name" ? "first_name" : "mobile_number"
  }) //<=== set state of value header
}

    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</th>
                        <th className='p-2' onClick={toggleSort}>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>
            
        </div>
    )
}

export default Table

The problem is that regardless of which column I click on, the table is only sorted based on the mobile column. I tried to find the problem, it seems that even after clicking on a column header, the value of target.value becomes undefined and as a result, even when I click on name column, the value of valueHeader.body becomes mobile based on the logic used in the toggleSort function, so the table is sorted based on mobile column. How can I solve this?

CodePudding user response:

event.target.value is accessible only on event

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

const Table = () => {

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


    useEffect(async () => {
    try {
        const response = await getUsers(search);
        setUsers(response.data.users);
    } 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
}

    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>
            
        </div>
    )
}

export default Table
  • Related