alswlfl 2022. 11. 16. 22:38

useRef

useRef로 특정 DOM 선택하기

★ DOM(문서 객체 모델): XML이나 HTML문서에 접근하기 위한 일종의 인터페이스, 이 객체 모델은 문서 내의 모든 요소를 정의하고, 각각의 요소에 접근하는 방법 제공

  • 자바스크립트에서는 특정 DOM을 선택해야 하는 상황에 getElementById, querySelector 같은 DOM. Selector 함수를 사용해서 DOM 선택
  • 리액트에서는 ref사용
  1. 함수형 컴포넌트: useRef라는 Hook 함수 사용
  2. 클래스형 컴포넌트: 콜백 함수 사용하거나 React.createRef라는 함수 사용

useRef사용 이유

  • 값 저장: 현재 저장하고 싶은 값을 리렌더링 없이 저장
  • DOM 참조: DOM참조가능, 현재 DOM에서 element의 scroll위치, image의 size 등을 참조할 수 있다.
  • useState로 관리하게 되면, 리렌더링이 계속 발생하므로 비효율적이고, 코드 구현하기 어려워짐
import React, { useState, useRef } from "react";

function InputSample() {
  const [inputs, setInputs] = useState({
    name: "",
    nickname: "",
  });
  const nameInput = useRef();

  const { name, nickname } = inputs;//비구조화 할당을 통해 값 추출const onChange = (e) => {
    const { value, name } = e.target;//우선 e.target에서 name과 value를 추출
    setInputs({
      ...inputs,//기존의 input객체 복사한 뒤
      [name]: value,//name키를 가진 값을 value로 설정
    });
  };
  const onReset = () => {
    setInputs({
      name: "",
      nickname: "",
    });
    nameInput.current.focus();//onReset함수에서 input에 포커스하는 focus() DOM API
  };
  return (
    <div>
      <input
        name="name"
        placeholder="이름"
        onChange={onChange}
        value={name}
        ref={nameInput}
      />
      <input
        name="nickname"
        placeholder="닉네임"
        onChange={onChange}
        value={nickname}
      />
      <button onClick={onReset}>초기화</button>
      <div>
        <b>값:</b>
        {name} ({nickname})
      </div>
    </div>
  );
}

export default InputSample;
  • useRef()를 사용하여 Ref 객체를 만들고, 이 객체를 우리가 선택하고 싶은 DOM에 ref값으로 설정해주어야 함
  • Ref객체의 .current값은 우리가 원하는 DOM 을 가리키게 됨

배열 렌더링

import React from "react";

function User({ user }) {
  return (
    <div>
      <b>{user.username}</b> <span>({user.email})</span>
    </div>
  );
}

function UserList() {
  const users = [
    { id: 1, username: "velopert", email: "public.velopert@gmail.com" },
    { id: 2, username: "tester", email: "tester@example.com" },
    { id: 3, username: "liz", email: "liz@example.com" },
  ];
  return (
    <div>
      <User user={users[0]} />
      <User user={users[1]} />
      <User user={users[2]} />
    </div>
  );
}

export default UserList;
  • 배열이 고정적이면 괜찮지만, 배열 인덱스 하나하나 조회하며 렌더링하는 방법은 동적인 배열 렌더링 못함

동적인 배열 렌더링 방법

: 자바스크립트 배열의 내장함수 map() 사용, 이 함수를 사용하여 일반 데이터 배열을 리액트 엘리먼트로 이루어진 배열로 변환

⭐️ map: 배열 안의 각 원소를 변환하여 새로운 배열을 만들 때 사용

  • 리액트에서 배열 렌더링 할 때, key라는 props 설정해야함

►key 값은 각 원소들마다 가지고 있는 고유값으로 설정

import React from "react";

function User({ user }) {
  return (
    <div>
      <b>{user.username}</b> <span>({user.email})</span>
    </div>
  );
}

function UserList() {
  const users = [
    { id: 1, username: "velopert", email: "public.velopert@gmail.com" },
    { id: 2, username: "tester", email: "tester@example.com" },
    { id: 3, username: "liz", email: "liz@example.com" },
  ];
  return (
    <div>
      {users.map((user) => (
        <User user={user} key={user.id} />
      ))}
    </div>
  );
}

export default UserList;
  • 배열을 렌더링 할 때 key 설정하지 않으면 기본적으로 배열의 index값을 key로 사용하고, 경고 메시지가 뜸

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

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

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

key가 없을 때,

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

array.map(item=><div>{item}</div>);

Q. b와 c 사이에 z를 삽입하는 경우

A. 리렌더링 시,  <div>b</div>와 <div>c</div>사이에 새로운 div태그를 삽입하는 것이 아니라, 기존의 c가 z로 바뀌고,  d는 c로 바뀌고, 맨 마지막에 d가 새로 삽입

Q. a를 제거하는 경우

A. 기존의 a가 b로 바뀌고, b는 z로 바뀌고, z는 c로 바뀌고, c는 d로 바뀌고, 맨 마지막에 있는 d제거

즉, key가 존재하지 않을 때, 기존에 있던 값을 건들이면서 업데이트

 

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가 있을 때, 렌더링 시 오류메시지가 콘솔에 나타나 업데이터가 제대로 이루어지지 않음

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

useRef의 용도

  1. DOM 선택
  2. 컴포넌트 안에서 조회 및 수정 할 수 있는 변수 관리
  • setTimeout, setInterval을 통해서 만들어진 id
  • 외부 라이브러리를 사용하여 생성된 인스턴스
  • scroll위치 ▸ [react] scroll event (테스트)
import React from "react";

function User({ user }) {
  return (
    <div>
      <b>{user.username}</b> <span>({user.email})</span>
    </div>
  );
}

function UserList({ users }) {
  return (
    <div>
      {users.map((user) => (
        <User user={user} key={user.id} />
      ))}
    </div>
  );
}

export default UserList;
import React, { useRef } from "react";
import UserList from "./UserList";

function App() {
  const users = [
    {
      id: 1,
      username: "velopert",
      email: "public.velopert@gmail.com",
    },
    {
      id: 2,
      username: "tester",
      email: "tester@example.com",
    },
    {
      id: 3,
      username: "liz",
      email: "liz@example.com",
    },
  ];

  const nextId = useRef(4); //useRef() 사용할 때 파라미터 넣어주면, 이 값이 .current값의 기본값이 됨
  const onCreate = () => {
    nextId.current += 1; //값 수정 시, .current 값 수정하면 되고, 조회할 때도 .current조회하면 됨
  };
  return <UserList users={users} />;
}

export default App;