본문 바로가기

WINK-(Web & App)/React.js 스터디

[2025 1학기 React.js 스터디] 이상래 #4주차

반응형

되게 오랜만이라.... 그래서 다 까먹어버림 ㅋㅋ

전에 했던거 슥 보고 시작!

 

초 긍정마인드

 

🔍 useRef 로 특정 DOM 선택하기

리액트에서도 DOM을 직접 선택해야 하는 상황이 있다 !!

 

ex) 1. 특정 엘리먼트의 크기를 가져와야 할 때

      2. 포커스를 설정 해줘야 할 때 

      3. 외부 라이브러리를 사용해야 할 때 등등

 

ref - useRef

 

useRef: Hook 함수

 

getElementById, querySelector 같은 Selector 함수를 사용하는 자바스크립트와는 다르게

리엑트에서는 ref라는 걸 사용합니다. (함수형 컴포넌트에서 사용)

 

 

저번에 작성했던 InputSample 코드에 useRef를 추가했어요

추가된건 다음 3줄인데요

const nameInput = useRef();

useRef()를 사용해 Ref 객체 nameInput을 생성함

nameInput.current.focus();

생성한 객체를 현재 DOM에 focus() 메서드 호출/ 해당 요소에 포커스를 줌

ref={nameInput}

해당 DOM요소에 nameInput이라는 ref를 연결(nameInput.current가 이 코드가 있는 요소를 가리킴)

 

이렇게 초기화 누르면 focus가 됩니다 !!

 

🔍 배열 렌더링하기

이번 배열을 렌더링 하는 방법을 배워볼게요

이런 배열을 예시로 쓸게요

  1.  그냥 그대로 코드 작성하기

 

왼쪽 처럼 그냥 주어진 배열을 그대로 작성해도 되지만 재사용되는 코드를 줄여서 오른쪽처럼 만들 수 있습니다 !!

왼쪽 코드의 단점

  • 확장성 부족: user가 100명이면 100줄을 써야 함.
  • 재사용 불가: user를 별도로 컴포넌트화 하지 않아 다른 곳에서 재활용 불가

❓왜 컴포넌트화 할 때 id는 안넘기나

A: id가 컴포넌트에서 직접적으로 사용되지 않기 때문에

-화면에 보여주는 것은 usernamerhk email뿐이므로 굳이 전달할 필요가 없다.

 

🧠 필요한경우 

  1. 리스트를 렌더링할 때 key로 사용하기 위해
return (
  <div>
    {users.map(user => (
      <User key={user.id} user={user} />
    ))}
  </div>
);

여기서는 식별할 때 key로 사용

 

2. 내부 특정 동작에서 id가 필요할 때

function User({ user, onRemove }) {
  return (
    <div>
      <b>{user.username}</b> <span>({user.email})</span>
      <button onClick={() => onRemove(user.id)}>삭제</button>
    </div>
  );
}

이 경우에는 id도 간접적으로 사용되므로 id도 넘겨주어야 한다!!

 

다시 돌아와서 위에서 했던 방법들은 동적인 배열을 렌더링 하지 못함

그래서 !! 동적인 배열을 렌더링해야 할 때는 자바스크립트 배열의 내장함수 map()을 사용

 

map() 함수

 

배열안에 있는 각 원소를 변환하여 새로운 배열을 만들어줌

리액트에서 동적인 배열을 렌더링해야 할 때 일반 데이터 배열을 리액트 엘리먼트로 이루어진 배열로 변환

 

이렇게 map을 쓰면 결과적으로 User컴포넌트가 배열의 길이만큼 생성 => <div>안에 나열됨

 

 

근데 이렇게 하면 에러가 있다고 뜬다!!

아까 왜 id는 안하는지 찾아봤었는데 react에서 배열을 렌더링 할 때에는 key 라는 props를 설정해야 한대요

-key 값은 각 원소들마다 가지고 있는 고유값으로 설정을 해야함(지금의 경우엔 id가 고유 값)

 

 

❓ 그럼 그냥 무조건 id도 넘겨야 했던거 아닌가????

근데 이 코드를 보면 여전히 User컴포넌트를 만들 때 id를 넘기는게 아니라 map()에서 직접 설정 하고 있다..

 

 

✅ 왜 key User컴포넌트에 넘기지 않고, map() 에서 직접 쓰는가?

      - Key는 React 내부에서만 사용됨

  • key컴포넌트의 props가 아님
  • React가 리스트 항목을 구분해서 효율적으로 리렌더링하기 위해 내부적으로 쓰는 값이에요
  • 그래서 User 컴포넌트에서는 props.key로 접근할 수 없습니다

    - Key는 컴포넌트 외부에서 설정해야 함

{users.map((user) => (
  <User key={user.id} user={user} />
))}

이렇게 해야 react가 각 컴포넌트의 위치를 식별/성능 최적화를 할 수 있음

 

배열 안의 원소가 가지고 있는 고유한 값이 없다면 map() 함수를 사용 할 때 설정하는 콜백함수의 두번째 파라미터 index  key 로 사용

<div>
  {users.map((user, index) => (
    <User user={user} key={index} />
  ))}
</div>

 

💡 key의 존재유무에 따른 업데이트 방식

const array = ['a', 'b', 'c', 'd'];

array.map(item => <div>{item}</div>); //key값 없이

[
  {
    id: 0,
    text: 'a'
  },
  {
    id: 1,
    text: 'b'
  },
  {
    id: 2,
    text: 'c'
  },
  {
    id: 3,
    text: 'd'
  }
];

array.map(item => <div key={item.id}>{item.text}</div>); //key값 사용

 

- key값이 없으면 삽입/삭제시에 하나하나 원소를 바꾸는 방식으로 진행되서 비효율적

- key값이 있으면 그런 과정 없이 바로 바로 삽입/삭제 => 효율적

 

🔍 useRef 로 컴포넌트 안의 변수 만들기

useRef의 용도

 

1. DOM을 선택하는 용도 (위에서 다룸)

 

2. 컴포넌트 안에서 조회 및 수정 할 수 있는 변수 관리

   - 값이 바뀌어도 컴포넌트 리렌더링 x 

   - 설정 후 바로 조회 가능

   -다음과 같은 값을 관리 할 수 있음

  • setTimeout, setInterval 을 통해서 만들어진 id
  • 외부 라이브러리를 사용하여 생성된 인스턴스
  • scroll 위치

useRef로 변수를 관리하기 전에 배열을 APP.js에서 선언하고 UserList에게 props로 전달을 해주는 방식으로 바꿔줬습니다

 

  • useRef()에 들어가는 파라미터 = .current 값의 기본값
  • 예제에서는 이미 id가 3까지 만들어져 있어서 4로 설정
  • 수정할 때는 .current 값을 수정 조회할 때도 .current 조회

 

🔍 배열에 항목 추가하기

 

우선 새로운 User를 추가해주는 컴포넌트를 만들고
App에다 렌더링까지 해주고

 

💡 배열에 변화를 줄 때

  • 객체와 마찬가지로 불변성을 지켜야함 !
  • 배열의 push, splice, sort 등의 함수 사용 x
  • 사용 하려면 기존 배열 복사하고 나서 사용

새 항목을 추가하는 방법

    1.spread 연산자 사용

 

  • input 요소에서 값이 바뀌면 바뀐 부분 업데이트
  • ...input으로 기존 상태 복사/유지 후 변경된 값만 덮어씌움
  • setUsers로 새로운 사용자 추가 가능
  • 새로운 생성되는 사용자는 id = 4로 설정 이후 1씩 증가
  • username과 email을 받아서 새로운 사용자 객체 생성후 배열 업데이트
  • 입력값 초기화

  2.concat 함수 사용

이 부분만 이렇게 바꾸면 된다!

concat 함수

 

  • JavaScript 배열의 기존 배열을 변경하지 않고, 새로운 요소를 추가한 새로운 배열을 반환하는 메서드
  • spread (...) 연산자와 기능은 비슷하지만 문법이 다름
  • 원본배열.concat(새로 추가할 요소 or 배열)

 

🔍 배열 항목 제거하기

  • 배열을 추가 하는 것과 마찬가지로 제거하는 것도 배열에 변화를 주는 것!
    • => 불변성을 지켜야함. (filter 배열 내장 함수를 사용하는 것이 가장 편리)
filter() 함수

 

  • JavaScript 배열 메서드 
  • 배열에서 특정 조건을 만족하는 요소들만 골라 새로운 배열을 만들 때 사용

 

- onRemove를 만들어서 파라미터로 주어진 id와 다른 값을 가진 user들만 모은 새 배열을만듬

        => 불변성을 지킴, 해당 id를 가진 user 삭제

 

 

이런식으로 삭제 버튼을 누르면 삭제가 되는 것을 확인 할 수 있습니다!!

 

🔍 배열 항목 수정하기

항목을 수정하는것도.... 배열에 변화를 주는 것이기 때문에!

불변성을 유지해 줘야겠죠??

 

예제는 유저명을 누르면 초록색 글씨로 on/off 하는 것....

 

 

 

  • User를 만들때 onToggle까지 전달
  • active가 true면 초록색으로 바꿈
  • 클릭되면 onToggle을 이용해서 해당 id에 해당되는 유저명의 active값을 바꿔줌

❓ &nbsp

하다가 이게 코드에 있길래 궁금해서 찾아봤습니다!!

: non-breaking space

: 일반 공백( )과 달리, 줄바꿈이 생겨도 이 공백에서는 줄이 안 바뀜

 

📦 언제 사용하나?

  • 텍스트 사이를 강제로 띄우고 싶을 때
  • 줄바꿈 없이 항상 붙어있게 하고 싶을 때
  • 여러 개 연속 띄어쓰기를 표현하고 싶을 때 (HTML에선 보통 띄어쓰기 여러 개가 1개처럼 보임)
  • 예제 코드에서는 그냥 한 칸 띄우려고 사용

 

🔍 useEffect를 사용하여 마운트/언마운트/업데이트시 할 작업 설정하기

useEffect

 

  • Hook중 하나
  • 컴포넌트가 렌더링된 이후에 어떤 “부수 효과(side effect)“를 수행하고 싶을 때 사용
  • ex)
    • 데이터를 가져오기 (fetch)
    • 타이머 설정
    • 이벤트 리스너 등록
    • 로컬스토리지 접근 등

💡 기본문법 

import { useEffect } from "react";

useEffect(() => {
  // 여기에 부수 효과 코드를 작성
  console.log("컴포넌트가 렌더링되었어요!");

  // 클린업 함수 (선택적)
  return () => {
    console.log("컴포넌트가 언마운트되거나, 다시 실행되기 전 정리됩니다.");
  };
}, [/* 의존성 배열 */]);
  • 첫 번째 파라미터에는 함수
  • 두 번째 파라미터에는 의존값이 들어있는 배열

오호라

 

주로 마운트 시에 하는 작업들 
  1. props로 받은 값을 컴포넌트의 로컬 상태로 설정
  2. 외부 API요청 
  3. 라이브러리 사용
  4. setInterval을 통한 반복작업 혹은 setTimeout을 통한 작업 예약
주로 언마운트 시에 하는 작업들
  1. setInterval, setTimeout 을 사용하여 등록한 작업들 clear 하기 (clearInterval, clearTimeout)
  2. 라이브러리 인스턴스 제거

 

👀 마운트 / 언마운트

 

이렇게 하면

  • 의존성 배열이 빈 배열 => 처음 마운트될 때 한 번만 실행
  • return () => {} 함수는 언마운트 될 때 실행

👀 deps에 특정 값 넣기 

: 컴포넌트가 처음 마운트 될 때/ 지정한 값이 바뀔 때 호출

: deps안에 특정 값이 있다면 언마운트시/ 값이 바뀌기 직전에 호출

 

이렇게 의존성 배열에 값을 넣어줌
이렇게 호출됨

: useEffect 안에서 사용하는 상태 / props가 있다 >> useEffect의 deps에 넣어주어야 함

만약 넣지 않으면 useEffect에 등록한 함수가 실행 될 때 최신 props / 상태를 가르키지 않게 됨

 

👀 deps 파라미터를 생략하기

: 컴포넌트가 리렌더링 될 때마다 호출

 

이렇게 의존성 배열을 생략하면

 

이렇게 삭제하거나 추가하면 리렌더링 되는데, 그때 마다 호출

++ 기본적으로 부모 컴포넌트가 리렌더링 되면 자식 컴포넌트도 리렌더링됨.

 

휴... 오랜만에 하니까 좀 힘들고.... 어렵고..... 다시 화이팅 ㅠ

 

반응형