React에서 key 속성은 컴포넌트의 리스트를 렌더링할 때 매우 중요한 역할을 합니다. 이 속성은 React가 어떤 항목이 변경, 추가 또는 제거되었는지 효율적으로 식별할 수 있도록 돕습니다. 이를 통해 업데이트 과정을 최적화하고, 불필요한 리렌더링을 피할 수 있습니다. 이번 포스팅에서는 key 속성의 중요성과 올바른 사용법에 대해 깊이 있게 알아보겠습니다.

key 속성이 중요한 이유

React는 효율적인 DOM 조작을 위해 가상 DOM을 사용합니다. 가상 DOM은 실제 DOM에 반영되기 전에 메모리 내에서 상태 변화를 시뮬레이션합니다. 이 과정에서, React는 각 컴포넌트의 변화를 추적하고, 최소한의 변경 사항만 실제 DOM에 반영하려고 합니다. key 속성은 이 과정에서 중요한 역할을 합니다. 유니크한 key 값을 통해 어떤 항목이 변화했는지 정확히 파악할 수 있기 때문입니다.

key 속성 사용법

  1. 리스트에서 고유한 값 사용
    const todoItems = todos.map((todo) =>
      <li key={todo.id}>
        {todo.text}
      </li>
    );
    
    
  2. key는 리스트 내에서 각 항목을 고유하게 식별할 수 있는 값을 사용해야 합니다. 보통 데이터베이스의 고유 ID나, 항목의 인덱스를 사용할 수 있습니다. 하지만 인덱스는 항목이 추가되거나 삭제될 때 문제가 생길 수 있으므로, 고유 ID를 사용하는 것이 좋습니다.
  3. key는 형제 사이에서만 유일하면 됨
    function Blog({ posts }) {
      const sidebar = (
        <ul>
          {posts.map((post) =>
            <li key={post.id}>
              {post.title}
            </li>
          )}
        </ul>
      );
      const content = posts.map((post) =>
        <div key={post.id}>
          <h3>{post.title}</h3>
          <p>{post.content}</p>
        </div>
      );
      return (
        <div>
          {sidebar}
          <hr />
          {content}
        </div>
      );
    }
    
    
  4. key 속성은 형제 요소 사이에서만 유일하면 됩니다. 전체 애플리케이션에서 유일할 필요는 없습니다.
  5. 고유한 값이 없다면
    const items = list.map((item, index) =>
      <li key={`${item.name}-${item.type}`}>
        {item.name}: {item.type}
      </li>
    );
    
    
  6. 만약 고유한 ID가 없다면, 다른 고유한 문자열을 생성해서 사용할 수도 있습니다. 예를 들어, 데이터의 각 속성을 조합하여 고유한 문자열을 만들 수 있습니다.

key 속성 사용 시 주의사항

  • 고유성 보장: key 값이 중복되지 않도록 해야 합니다. 중복된 key 값은 React가 항목을 제대로 식별하지 못하게 하여 렌더링 오류를 발생시킬 수 있습니다.
  • 인덱스 사용의 신중함: 인덱스를 key로 사용하는 것은 리스트 항목이 순서에 따라 변경되지 않는 경우에만 권장됩니다. 그렇지 않으면, 항목의 추가, 삭제 시 문제가 발생할 수 있습니다.
  • 불변성 유지: key 값은 변하지 않아야 합니다. key 값이 변경되면, React는 해당 항목을 새롭게 생성된 것으로 인식하게 됩니다.

결론

React에서 key 속성은 리스트 렌더링의 핵심 요소입니다. 올바른 key 사용법을 이해하고 적용하면, 애플리케이션의 성능과 안정성을 크게 향상시킬 수 있습니다. 항상 고유한 key 값을 사용하고, 인덱스를 key로 사용하는 경우에는 신중을 기하는 것이 중요합니다. 이제 여러분도 key 속성을 잘 활용하여 효율적인 React 애플리케이션을 만들어 보세요!


이 글이 도움이 되셨다면, 좋아요와 공유 부탁드립니다! React와 관련된 더 많은 유용한 정보를 얻고 싶으시면, 저희 블로그를 구독해 주세요. 다음 포스팅에서 또 만나요! 🚀

React의 forwardRef는 부모 컴포넌트로부터 자식 컴포넌트로 ref를 전달할 수 있게 해주는 고차 함수입니다. 이를 통해 부모 컴포넌트가 자식 컴포넌트의 DOM 요소나 컴포넌트 인스턴스에 접근할 수 있습니다. forwardRef의 기본 사용법과 동작 원리에 대해 설명해드리겠습니다.

forwardRef 기본 사용법

  1. 기본 개념: forwardRef는 함수형 컴포넌트를 작성할 때 사용하며, 부모로부터 전달받은 ref를 자식 컴포넌트의 특정 DOM 요소나 컴포넌트 인스턴스에 전달합니다.
  2. 사용법: 다음과 같은 형태로 forwardRef를 사용할 수 있습니다.위 코드에서 MyInput 컴포넌트는 forwardRef를 사용하여 전달받은 ref를 <input> 요소에 전달합니다. 이렇게 하면 부모 컴포넌트가 MyInput 컴포넌트의 DOM 요소에 직접 접근할 수 있습니다.
  3. import React, { forwardRef } from 'react'; const MyInput = forwardRef((props, ref) => ( <input {...props} ref={ref} /> )); export default MyInput;
  4. 부모 컴포넌트에서의 사용: MyInput 컴포넌트를 사용하는 부모 컴포넌트에서는 다음과 같이 ref를 사용할 수 있습니다.이 코드에서 inputRef는 MyInput 컴포넌트 내부의 <input> 요소를 참조하게 되며, 버튼을 클릭하면 해당 입력 필드에 포커스를 설정할 수 있습니다.
  5. import React, { useRef } from 'react'; import MyInput from './MyInput'; const ParentComponent = () => { const inputRef = useRef(null); const focusInput = () => { if (inputRef.current) { inputRef.current.focus(); } }; return ( <div> <MyInput ref={inputRef} /> <button onClick={focusInput}>Focus Input</button> </div> ); }; export default ParentComponent;

forwardRef의 이점

  • 캡슐화 유지: forwardRef를 사용하면 컴포넌트의 내부 구조를 외부에 노출하지 않고도 내부 DOM 요소에 접근할 수 있습니다. 이는 컴포넌트의 캡슐화를 유지하면서도 필요한 기능을 제공할 수 있게 합니다.
  • 유연성 제공: 부모 컴포넌트가 자식 컴포넌트의 특정 요소에 접근해야 하는 경우, 예를 들어 폼 요소에 포커스를 맞추거나, 특정 애니메이션을 적용해야 할 때 유용합니다.

요약

forwardRef는 React에서 고차 함수로, 부모 컴포넌트가 자식 컴포넌트의 DOM 요소나 인스턴스에 접근할 수 있게 해줍니다. 이를 통해 컴포넌트의 재사용성을 높이고, 캡슐화를 유지하면서도 유연한 DOM 조작을 가능하게 합니다. 위 예제를 통해 forwardRef의 기본 사용법과 장점을 이해할 수 있습니다.

useRef()훅은 포인터와 비슷한 느낌으로사용할수있습니다

useRef()훅은 DOM객체들을 참조할수도있지만

참조를 어떤 종류의 값이든 제어하기위해 사용할수도 있습니다.

const timer =useRef()

timer 상수가 위의 참조를 보관하는것입니다.

여러개의 컴포넌트에서 timer를 변수로 만들거나 상태값으로 관리하게되면 여러개의 컴포넌트가 시작될때마다 함수가 재실행되어

timer변수의 포인터가 바뀝니다

하지만 useRef()를 이용하여 해당 컴포넌트의 참조를 만들어 각각의 컴포넌트가 따로 작동할수있게 만들수 있습니다

timer.current = setTimeout(()=>{
	alert("함수작동")
} , 1000)

setTimeout() 내장함수를 이용하여 1초후 알림창이 작동하는 코드입니다

참조를이용하면 해당 컴포넌트에서 1초후 작동할수있게 만들수 있습니다.

useRef()로 참조를이용하게되면 모든 컴포넌트 인스턴스들은 자기들만의 timer참조를 갖을것입니다.

리액트로 웹사이트를 개발할 때는 선언적 프로그래밍 방식을 사용하는 것을 권장합니다.

선언적 프로그래밍은 명령형 프로그래밍과 반대되는 개념입니다. 예를 들어, 바닐라 JS를 사용하는 방법은 명령형 프로그래밍의 한 예로, 이는 특정 DOM 요소를 지정하고 그 요소에 변화를 주며 명령을 내려 프로그래밍하는 방식입니다.

리액트에서는 DOM을 직접적으로 변화시키거나 접근하는 방식으로 프로그래밍할 경우 오류가 발생할 수 있으며, 이는 권장되지 않는 방법입니다. 대신, 리액트는 상태를 관리하며 선언적 프로그래밍 방식을 사용하도록 설계되었습니다.

useRef() 훅: DOM을 참조하는 리액트 내장 훅

리액트에서는 useState() 훅을 사용하여 상태를 관리하며 프로그래밍하는 것이 기본적인 방법입니다. 하지만 useState()를 사용하면 코드가 길어질 수 있고 가독성이 떨어질 수 있으며, 상태값이 변경될 때마다 리액트 컴포넌트가 재실행되어 불필요한 리렌더링이 발생할 수 있습니다.

이 문제를 해결하기 위해 useRef 훅을 사용할 수 있습니다. useRef는 리액트 라이브러리에 내장된 훅이며, import를 통해 불러올 수 있습니다:

import { useState, useRef } from "react";

export default function Player() {
  const playerName = useRef();
}

JSX 문법이 적용되는 모든 HTML 태그들에는 ref={} 속성을 추가할 수 있으며, 이를 통해 해당 DOM을 참조할 수 있습니다:

<input ref={playerName} type="text" />

상수로 설정한 playerName을 사용하는 방법은 다음과 같습니다:

playerName.current
playerName.current.value

이렇게 current 속성을 통해 해당 HTML 태그의 모든 속성에 접근할 수 있습니다.

⚠️ useRef() 훅은 current 객체를 반환합니다.

useRef 훅이 반환하는 객체는 기본적으로 단 하나의 속성, current, 만을 가지고 있습니다. 이 속성이 ref가 참조하는 값을 저장합니다. useRef 훅을 사용하면 다음과 같은 객체가 생성됩니다:

const ref = useRef(initialValue);

이 객체는 다음과 같은 구조를 가집니다:

{
  current: initialValue
}

따라서 current 이외에 다른 속성을 가지지 않습니다. useRef 훅은 매우 단순하게 설계되어 있어, 오직 current 속성을 통해서만 값을 접근하고 변경할 수 있습니다.

npm install styled-components

styled-somponents는 리액트에서 스타일을 적용시키는 특별한 컴포넌트를 만드는 패키지입니다.

리액트의 컴포넌트 처럼 사용할수있습니다.

❗기존 css로는 className을 통하여 해당스타일링을 반복적으로 요소하나하나에 작성해야함


styled-components 사용방법

import {styled} from 'styled-components'

const Div = styled.div`
	color: 'red';
	font-size : '10px';
`
// 스타일드 컴포넌트 사용법
<Div> 이렇게 사용합니다 </Div>

styled-components를 적용시키기위해선 해당 파일에서 styled객체를 불러옵니다

styled객체는 jsx문법에 맞는 html tag들을 가지고있습니다.

``(백틱)을 이용하여 기존의 css문법을 그대로 적용시킬수 있습니다.


동적 스타일링 지정방법

전통적인 css className을 이용하는법

//전통적인 css class명을 삼항연산자를 통하여 조건에 맞추어 클래스를 바꿔주는방법
<Label className={`label ${emailNotValid ? 'invalid' : ''}`}>Email</Label>

이 방법은 전통적인 css로 스타일을 지정하는 방법 입니다.표현식을 넣을수있는 jsx 문법에 맞추어

삼항연산자로 논리값 (true false)에 맞추어 어떤 클래스를 적용시킬지를 작성했습니다.


리액트 컴포넌트의 props속성을 이용하여 하는방법

const Label = styled.label`
    display: block;
  margin-bottom: 0.5rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: ${(props) => props.$invalid ? "#f87171" : "#6b7280"};
`
 <Label $invalid={emailNotValid}>Email</Label>

Label 스타일드 컴포넌트를 만든다음 내가 적용시키고싶은 css코드를 `` (백틱)사이에 넣어 줍니다.

스타일드 컴포넌트는 리액트컴포넌트처럼 ‘props’ 속성등을 이용할수있는데 invalida={} 속성에 논리값을 넣어서 작동하게 할수있습니다.

해당 스타일컴포넌트를 정의한곳에서 는 `` 백틱 안에 ${…} 으로 자바스크립트 표현식을 작성하는곳에 props로 전달된 invalid속성을 사용할수있습니다.

❗ 중요한 포인트

속성 값으로 전달될 이름앞에 $사인을 붙여야합니다.

일반적으로 styled-components에서 속성을 정의할 때, 전달된 속성 이름 앞에 "$" 기호를 붙여서 해당 속성을 transient prop(임시 속성)으로 지정합니다. 이렇게 하면 styled-components가 해당 속성을 DOM으로 전달하지 않고, 컴포넌트 내에서만 사용할 수 있게 됩니다.


마무리

스타일드 컴포넌츠 (styled-components) 패키지는 전통적인 css방식보다 좀더 “리액트”스러운 방식으로 재사용이 가능한 스타일이된 컴포넌트 들을 만들수있습니다 그렇기에 사용이 되는것 이구요

아래의 예시처럼 스타일을 손쉽게 꾸밀수있으며 해당 속성을 기반으로 조건부 렌더링이 가능합니다.

단점으로는 수많은 wrapper들이 생길수있습니다. 

import { styled } from 'styled-components'

const Label = styled.label`
    display: block;
    margin-bottom: 0.5rem;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: ${(props) => props.$invalid ? "#f87171" : "#6b7280"};
`
const Input = styled.input`
    width: 100%;
    padding: 0.75rem 1rem;
    line-height: 1.5;
    background-color: ${props => props.$invalid ? '#Fed2d2' : '#d1d5db'};
    color: ${props => props.$invalid ? "#ef4444" : "#374151"};
    border: 1px solid ${props => props.$invalid ? "#f73f3f" : "transparent"};
    border-radius: 0.25rem;
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
`

const CustomInput = ({ label, invalid, ...props }) => {
    return (
        <p>
            <Label $invalid={invalid}>{label}</Label>
            <Input $invalid={invalid} {...props} />
        </p>
    )
}
export default CustomInput;
npm install styled-components

styled-somponents는 리액트에서 스타일을 적용시키는 특별한 컴포넌트를 만드는 패키지입니다.

리액트의 컴포넌트 처럼 사용할수있습니다.

❗기존 css로는 className을 통하여 해당스타일링을 반복적으로 요소하나하나에 작성해야함


styled-components 사용방법

import {styled} from 'styled-components'

const Div = styled.div`
	color: 'red';
	font-size : '10px';
`
// 스타일드 컴포넌트 사용법
<Div> 이렇게 사용합니다 </Div>

styled-components를 적용시키기위해선 해당 파일에서 styled객체를 불러옵니다

styled객체는 jsx문법에 맞는 html tag들을 가지고있습니다.

``(백틱)을 이용하여 기존의 css문법을 그대로 적용시킬수 있습니다.


동적 스타일링 지정방법

전통적인 css className을 이용하는법

//전통적인 css class명을 삼항연산자를 통하여 조건에 맞추어 클래스를 바꿔주는방법
<Label className={`label ${emailNotValid ? 'invalid' : ''}`}>Email</Label>

이 방법은 전통적인 css로 스타일을 지정하는 방법 입니다.표현식을 넣을수있는 jsx 문법에 맞추어

삼항연산자로 논리값 (true false)에 맞추어 어떤 클래스를 적용시킬지를 작성했습니다.


리액트 컴포넌트의 props속성을 이용하여 하는방법

const Label = styled.label`
    display: block;
  margin-bottom: 0.5rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: ${(props) => props.$invalid ? "#f87171" : "#6b7280"};
`
 <Label $invalid={emailNotValid}>Email</Label>

Label 스타일드 컴포넌트를 만든다음 내가 적용시키고싶은 css코드를 `` (백틱)사이에 넣어 줍니다.

스타일드 컴포넌트는 리액트컴포넌트처럼 ‘props’ 속성등을 이용할수있는데 invalida={} 속성에 논리값을 넣어서 작동하게 할수있습니다.

해당 스타일컴포넌트를 정의한곳에서 는 `` 백틱 안에 ${…} 으로 자바스크립트 표현식을 작성하는곳에 props로 전달된 invalid속성을 사용할수있습니다.

❗ 중요한 포인트

속성 값으로 전달될 이름앞에 $사인을 붙여야합니다.

일반적으로 styled-components에서 속성을 정의할 때, 전달된 속성 이름 앞에 "$" 기호를 붙여서 해당 속성을 transient prop(임시 속성)으로 지정합니다. 이렇게 하면 styled-components가 해당 속성을 DOM으로 전달하지 않고, 컴포넌트 내에서만 사용할 수 있게 됩니다.


마무리

스타일드 컴포넌츠 (styled-components) 패키지는 전통적인 css방식보다 좀더 “리액트”스러운 방식으로 재사용이 가능한 스타일이된 컴포넌트 들을 만들수있습니다 그렇기에 사용이 되는것 이구요

아래의 예시처럼 스타일을 손쉽게 꾸밀수있으며 해당 속성을 기반으로 조건부 렌더링이 가능합니다.

단점으로는 수많은 wrapper들이 생길수있습니다. 하지만 리액트개발자라면 재사용이 가능한 컴포넌트로 꾸미는것은 무척이나 흥미로운 일입니다.

import { styled } from 'styled-components'

const Label = styled.label`
    display: block;
    margin-bottom: 0.5rem;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: ${(props) => props.$invalid ? "#f87171" : "#6b7280"};
`
const Input = styled.input`
    width: 100%;
    padding: 0.75rem 1rem;
    line-height: 1.5;
    background-color: ${props => props.$invalid ? '#Fed2d2' : '#d1d5db'};
    color: ${props => props.$invalid ? "#ef4444" : "#374151"};
    border: 1px solid ${props => props.$invalid ? "#f73f3f" : "transparent"};
    border-radius: 0.25rem;
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
`

const CustomInput = ({ label, invalid, ...props }) => {
    return (
        <p>
            <Label $invalid={invalid}>{label}</Label>
            <Input $invalid={invalid} {...props} />
        </p>
    )
}
export default CustomInput;

styled-components 사용방법

리액트에서는 vanilla css를 사용시에는 컴포넌트나 파일별로 css스코핑이 불가능하다

index.css 파일안에 스타일을 적용을시킬게되면 리액트앱 전체에 적용되며

header.css 와같이 헤더부분에 스타일을 지정하기 위해 파일을 분리시켜도 해당 css는 앱전역에 걸쳐 스타일링된다.

css modlues 적용하기

// Header.modlues.css

.paragraph {
    text-align: center;
    color: #a39191;
    margin: 0;
}
// Header.jsx

import classes from './Header.modlues.css'

 <p className={classes.paragraph}> 스타일이 적용될 문단 입니다.</p>

일반적인 css 나 js방식이 아닌 리액트만의 특별한 방법입니다

“modules” 라는 파일명을 확장자 앞에 넣어주게되면 리액트는 자동으로 해당파일을 해당컴포넌트에 css 모듈로 인식합니다 또한 css선택자의 중복문제를 해결해줄수있어 컴포넌트별로 스타일을 지정할수있습니다.

CSS modules의 장,단점

장점

  • css코드와 jsx코드를 독립적으로 스타일할수있습니다.
  • css 클래스명이 중복되지않습니다

단점

  • css를 알아야합니다.
  • 여전히 css를 사용합니다.
  • 작고,많은 css파일들이 있습니다.

리액트에서 동적인 스타일링을 적용하는 방법은 여러 가지가 있습니다. 그 중 가장 일반적인 방법은 인라인 스타일링, CSS 모듈, 그리고 styled-components를 사용하는 것입니다. 각각의 방법에 대해 설명드리겠습니다.

1. 인라인 스타일링

리액트에서는 스타일을 객체 형태로 인라인으로 적용할 수 있습니다. 스타일 속성은 CamelCase로 작성되어야 합니다.

import React from 'react';

function App() {
  const isRed = true;

  const style = {
    color: isRed ? 'red' : 'blue',
    backgroundColor: 'lightgray',
    padding: '10px'
  };

  return (
    <div style={style}>
      동적인 스타일링 예제
    </div>
  );
}

export default App;

2. CSS 모듈

CSS 모듈을 사용하면 각 컴포넌트마다 고유한 CSS 클래스를 정의할 수 있습니다. 파일 확장자는 .module.css를 사용합니다.

// App.module.css
.red {
  color: red;
}

.blue {
  color: blue;
}

// App.js
import React from 'react';
import styles from './App.module.css';

function App() {
  const isRed = true;

  return (
    <div className={isRed ? styles.red : styles.blue}>
      동적인 스타일링 예제
    </div>
  );
}

export default App;

3. styled-components

styled-components 라이브러리를 사용하면 자바스크립트 파일 안에서 CSS를 작성할 수 있습니다. 조건부 스타일링도 쉽게 할 수 있습니다.

npm install styled-components

// App.js
import React from 'react';
import styled from 'styled-components';

const DynamicDiv = styled.div`
  color: ${props => (props.isRed ? 'red' : 'blue')};
  background-color: lightgray;
  padding: 10px;
`;

function App() {
  const isRed = true;

  return (
    <DynamicDiv isRed={isRed}>
      동적인 스타일링 예제
    </DynamicDiv>
  );
}

export default App;

이 세 가지 방법 외에도 classnames 라이브러리 등을 사용하여 클래스를 동적으로 조합할 수도 있습니다. 선택한 방법은 프로젝트의 요구사항과 팀의 선호도에 따라 달라질 수 있습니다.

+ Recent posts