📢 어렵고 정석적인 개념 설명보다는 저같은 초보자도 이해하기 쉽게 정리하는 것을 원칙으로 포스팅하고 있습니다. 😄

[React] 리액트로 컴포넌트 간 데이터 정렬시키기

준비

const App = () => {
    return <div>
        <Home />
    </div>
}

const Home = () => {
    return <div>
        <SortMenu />
        <DataList />
    </div>
}

우선 이 글에서 다룰 목표는 컴포넌트끼리 데이터를 주고받는 과정에서, 그 데이터를 특정 기준에 맞춰서 정렬시키는 기능을 구현하는 것이다. 그 전에 이 프로젝트가 어떤 식으로 컴포넌트가 구성되는지 알 필요가 있다.

가장 큰 App 컴포넌트 안에 Home이라는 컴포넌트가 있고 그 안에 정렬 컴포넌트인 SortMenu와 정렬된 리스트를 출력할 DataList 컴포넌트가 구성되어 있다. (DataList 컴포넌트는 map() 함수를 통해 출력할 예정이다.)

 

방법

더미(dummy) 데이터 만들기

import { useState } from 'react';
import Home from './Home';

const App = () => {
    const dummyData = [{
        id: 1,
        name: "홍길동",
        content: "안녕하세요"
    }, {
        id: 2,
        name: "김영수",
        content: "안뇽안뇽~"
    }, {
        id: 3,
        name: "최창수",
        content: "반가워요!"
    }]

    const [data, setData] = useState(dummyData);

    return <div>
        <Home data={data} /> // Home 컴포넌트에 더미 데이터 전달
    </div>
}

export default Home;

우선 우리는 데이터를 서버에서 받아오지 못하므로 연습할 대상인 더미 데이터(dummy Data)를 만들어줘야 한다.

임의로 만든 더미 데이터는 id, name, content로 간단히 구성해주었고 id가 낮을수록 오래된 데이터, 높을수록 최신 데이터로 규정하여 추후 이 id를 기준으로 데이터를 정렬할 것이다.

 

정렬(select) 컴포넌트 만들기 

// Home 컴포넌트
const Home = () => {
    const [sortType, setSortType] = useState('lastest');
    const sortOptionList = [
        {value: 'lastest', name: '최신순'}, 
        {value: 'oldest', name: '오래된 순'}
    ];

    return <div>
        <SortMenu value={sortType} onChange={setSortType} optionList={sortOptionList}/>
    </div>
}

// SortMenu 컴포넌트
const SortMenu = ({ value, onChange, optionList }) => {
    return <select value={value} onChange={(e) => onChange(e.target.value)}>
        {optionList.map((it, idx) => (
            <option key={idx} value={it.value}>{it.name}</option>
        ))}
    </select>
}

정렬 컴포넌트인 SortMenu 컴포넌트에는 value, onChange, optionList라는 Props가 전달되는데 valueselect의 value 값, onChangeselect를 동작할 때 수행되는 함수, optionListselect의 옵션 리스트를 의미한다. 이 Props는 부모 컴포넌트인 Home에서 각각 정의해주었다.

 

정렬 함수 만들고 실행하기

const Home = () => {
    // 원본 데이터를 정렬시키고 정렬된 데이터를 반환하는 함수
    const getSortedList = () => {
        const compare = (a, b) => {
            if(sortType === 'lastest'){
                return parseInt(b.id - a.id); // 내림차순 정렬
            } else {
                return parseInt(a.id - b.id); // 오름차순 정렬
            }
        }
        
        const copyList = JSON.parse(JSON.stringify(data)); // 원본 데이터 복사
        const sortedList = copyList.sort(compare); // 데이터 정렬
        return sortedList; // 정렬된 데이터 반환
    }
    
    return <div>
        <SortMenu />
        {getSortedList().map(it => (
            <List key={it.id} {...it}>
        ))}
    </div>
}

여기서는 getSortedList 함수에 주목할 필요가 있다. 바로 우리의 목표였던 데이터를 정렬해주는 함수이기 때문이다.

이 함수는 원본 데이터를 복사하고, 그 복사한 데이터를 특정 기준에 맞춰 정렬시킨 다음 반환하는 기능을 수행한다.

 

정렬을 수행할 때 sort() 함수를 사용하는데, 보통 compare 비교 함수를 따로 만들어서 정렬하는 경우가 많다.

sort() 정렬 함수 관련된 건 블로그에 따로 정리해서 올려놓은 글(클릭)이 있으니 이 글에서의 자세한 설명은 생략하겠다.

 

또한 정렬을 수행할 때 유의해야할 점은 원본 데이터 자체를 건드리면 안 된다는 점이다.

따라서, copyList라는 변수에 원본 데이터를 복사해서 담아주었다. 데이터를 복사하는 방법 중 간단한 방법은 위처럼 JSON 함수를 이용하는 것이다. 현재 원본 데이터는 객체로 구성된 배열 형태이다.

JSON.stringify()로 배열([ ])을 문자화("[ ]")시켜 주고 JSON.parse()를 통해 다시 문자화된 배열("[ ]")을 원래 배열 형태([ ])로 바꿔주면 된다.

 

마지막으로 getSortedList().map()을 통해 정렬된 데이터들을 하나씩 출력하면 목표로 했던 정렬 기능이 제대로 구현된 것을 확인할 수 있을 것이다. 참고로 컴포넌트 간 데이터를 전달받고 정렬하는 방법은 위 방법으로 정형화된 게 아니다. 다른 부모-자식 컴포넌트를 만들고 다른 Props를 전달할 수 있다. 방법은 여러 가지이다.

단지, 가장 중요한 것은 리액트의 컴포넌트 동작 원리를 이해하는 것이다. 부모 컴포넌트와 자식 컴포넌트, 그리고 Props를 전달받고 전달하는 그 과정을 이해하자!

 

1. 정렬 함수는 어찌 됐든 데이터를 '출력'하는 기능이므로 데이터가 출력되는 컴포넌트에 구현해야 한다.
2. 정렬 함수는 원본 데이터를 복사하고, 정렬하고, 반환하는 총 3가지의 작업을 수행한다.
3. 정렬(<select />) 컴포넌트에는 value, onChange, optionList의 Props를 전달한다.