React Udemy #16: Data Sorting๐Ÿ˜ˆ

JEUNGBIN HANยท2023๋…„ 1์›” 6์ผ

React-Udemy-Lecture

๋ชฉ๋ก ๋ณด๊ธฐ
9/12
post-thumbnail

Sorting Data in JavaScript

data.sort()

  • Convert elements in the array to strings, then sort those
  • To fix this, we need to add a 'comparator' function
data.sort((a,d)=>{
  return a-b
})

5(b) ,1(a) ,4 ,3

  1. Should 'a' go before 'b'? return a negative number
  2. Should 'b' go before 'a'? return a positive number
  3. Are they the same? return 0 (Do not swap)

Sorting String

const data = ['a', 'b', 'A', 'B']

data.sort((a,b)=>{
  return a.lacaleCompare(b)
})

Sorting Objects

function getSortValue(data){
  return data.cost
}

 data.sort((a,b)=>{
   const valueA = getSortValue(a)
   const valusB = getSortValue(b)
   
   if(typeOf valueA ==='string'){
     return valueA.localeCompare(valueB)
   } else {
     return valueA - valueB
   }
 })

Reversing Sort Order

return (valueA - valueB) * -1

Better Solution

const sortOrder = 'asc'

data.sort((a,b)=>{
... 
const reverseOrder = sortOrder === 'asc' ? 1 : -1
...
return (valueA - valueB) * reverseOrder
})

Customizing Header Cells

Inside 'TablePage'

const config = [
    {
      label: "Name",
      render: (fruit) => fruit.name,
    },
    {
      label: "Color",
      render: (fruit) => <div className={`p-3 m-2 ${fruit.color}`}></div>,
    },
    {
      label: "Score",
      render: (fruit) => fruit.score,
      header: () => <th className="bg-red-500">Score</th>,
    },
  ];

Inside 'Table'

const renderHeaders = config.map((column)=>{
  if(column.header){
    return column.header()
  } else {
    return <th key={column.label}>{column.label}</th>;
  }
})

React Fragment

THERE IS KEY ISSUES! We are using 'Fragment'

import { Fragment } from "react";

export default function Table({ data, config, keyFn }) {
  const renderdHeaders = config.map((column) => {
    if (column.header) {
      return <Fragment key={column.label}> {column.header()}</Fragment>;
    }
    return <th key={column.label}>{column.label}</th>;
  });

Data sorting Component

data(array of objects) , config(labe, render)
=> Table Component

We've got a component that will render a table given an array of projects and a list of 'columns'.

We need one function to sort out Data

function getSortValue(fruit){
  return fruit.name
}
// sortOrder => 'asc' or 'desc'

where should we put getValue function?

Inside Object in Config
sortValue : optional function to describe how to extract values for sorting when this column clicked.

Inside 'TablePage'
data , config({label:'Name', render, sortValue})
=>
Inside 'SortableTable'

  • Look at eact object in the config array.
  • Does the object have a 'sortValue' function?
  • If so, this column must be sortable.
  • Add a 'header' property that will show a clickable header cell.
  • When user clicks this, sort the data and pass the sortedData to Table

=> 'Table'

Make a sortable Table

Adding a sortable Table

  1. Create SortableTable take all props and pass them through to Table
  2. Make sure TablePage shows SortableTable
  3. Add 'sortValue' functions to column config in TablePage. Remove 'header' properties.
//Inside 'TablePage'
const config = 
[
  labe:'Name',
  render:()=>{...},
  sortValue: (fruit)=>fruit.name
]
  1. SortableTable should find column objects with 'sortValue' and add a 'header' function to them
//Inside 'SortableTable'
function SortableTable(props){
  const {config} = props
  
  const updatedConfig = config.map((column)=>{
    if(!column.sortValue){
      reutrn column
    }
    
    return {...column,
      header:()=> <th>{column.label} Is sortable</th>
    }
  })
  return <Table {...props} config={updatedConfig}>
}
  1. TH returned by the 'header' function should watch for click event
  2. when a user clicks the TH, sort data and pass the result to Table

Adding Sort State

//Inside 'SortableTable'
  const [sortOrder, setSortOrder] = useState(null)
  cons [sortBy , setSortBy]  = useState(null)
  
  const handleClick = (label)=>{
    if(sortOrder === null){
      setSortOrder('asc');
      setSortBy(label)
    } else if (sortOrder === 'asc'){
      setSortOrder('desc');
      setSortBy(label)
    }  else if (sortOrder === 'desc'){
      setSortOrder(null);
      setSortBy(null)
    }
  }
  
  ...
  
   const updatedConfig = ...
   return {
     ...column,
     header:()=>{
       <th onClick={()=>hadleClick(column.label)}>{column.label}</th>
     }
   }
   ....

sort Data

//Inside SortableTable
  cosnt {config, data} = props
  ...
  // Only sort data when sortOrder&&sortBy are not null
  // Make a copy of the 'data' prop
  // Find the corrent sortValue function and use it for sorting
  
  let sortedData = data
  if(sortOrder && sortBy){
    const {sortValue} = config.find((column)=> column.label === sortBy)
    sortedData = [...data].sort((a,b)=>{
      const valueA = sortValue(a);
      const valueB = sortValue(b);
      
      const reverseOrder = sortOrder === 'asc' ? 1:-1;
      
      if(typsOf valueA === 'string'){
        return valueA.localeCompare(valueB) * reverseOrder
      } else {
        return (valueA - valueB) * reverseOrder
      }
    })
    
    return (
    <Table {...props} data={sortedData} config={updatedConfig}>
    
    )
  }

Determining icon set

//Inside 'SortableTable'
        <th onClick={() => handleClick(column.label)}>
          {getIcons(column.label, sortBy, sortOrder)}
          {column.label}
        </th>
        
//Outside
function getIcons(label, sortBy, sortOrder) {
  if (label !== sortBy) {
    return (
      <div>
        <GoArrowSmallUp />
        <GoArrowSmallDown />
      </div>
    );
  }

  if (sortOrder === null) {
    return (
      <div>
        <GoArrowSmallUp />
        <GoArrowSmallDown />
      </div>
    );
  } else if (sortOrder === "asc") {
    return (
      <div>
        <GoArrowSmallUp />
      </div>
    );
  } else if (sortOrder === "desc") {
    return (
      <div>
        <GoArrowSmallDown />
      </div>
    );
  }
}
profile
Web Developer

0๊ฐœ์˜ ๋Œ“๊ธ€