Front-end/React

[React]리액트 useRef 사용법

영벨롭 2022. 5. 29. 18:18

[ useRef ]

 

import { useRef } from "react";

const refContainer = useRef(initialValue);

<컴포넌트 ref={refContainer}></컴포넌트>

 

 useRef는 매번 렌더링을 할 때 동일한 ref 객체를 제공합니다.

 

 즉, 리렌더링 하지 않고 가상 DOM에서 컴포넌트의 속성을 조회&조작하고 그 결과물만 실제 DOM으로 전달합니다. 

 

 useRef는 current 속성을 가지고 있는 ref 객체를 반환하는데, 인자로 넘어온 initialValue를 current 속성에 할당합니다. 

 

 이 current 속성은 값을 변경해도 상태를 변경할 때 처럼 리액트 컴포넌트가 리렌더링되지 않고, 컴포넌트가 리렌더링될 때에도 current 속성 값은 유실되지 않습니다. 

 

 

 

 

[ 예제1 - 입력창에 자동 focus ]

 

 다음 예제는 제목과 본문을 작성할 수 있는 입력창을 구현한 모습입니다.

// src/Input.jsx
import React, { useState, useRef, useEffect } from 'react';

const Input = () => {
  const [input, setInput] = useState({
    title: '',
    contents: ''
  });

  const {title, contents} = input;
  const onChange = (e) => {
    const {value, name} = e.target;

    setInput({
      ...input,
      [name]: value
    })
  };

  return (
    <>
      <input type="text"
        name="title"
        value={title}
        placeholder="제목을 입력해주세요"
        onChange={onChange} />
      <br/>
      <textarea 
        name="contents"
        value={contents}
        cols="30"
        rows="10"
        onChange={onChange}></textarea>
    </>
  );
};

export default Input;

 

 

 위 코드에 useRef를 사용하여 페이지가 리렌더링 될때마다 제목 입력창에 focus가 자동으로 되고, 제목을 입력한 후 엔터키를 누르면 본문 입력창에 focus 되도록하겠습니다. 

 

 먼저 useRef를 사용하여 ref 객체를 생성한뒤, ref 속성을 통해 ref 객체를 연결합니다. 

 

// src/Input.jsx

...

  const titleInput = useRef();
  const contentsInput = useRef();
  
...

      <input type="text"
        name="title"
        value={title}
        placeholder="제목을 입력해주세요"
        onChange={onChange}
        ref={titleInput}    // ref
        onKeyUp={onKeyUp} />
      <br/>
      <textarea 
        name="contents"
        value={contents}
        cols="30"
        rows="10"
        onChange={onChange}
        ref={contentsInput}></textarea>   // ref

 

 콘솔창에 titleInput.current와 contentsInput.current 를 출력해보겠습니다!

 

 ref 객체가 잘 연결된 것을 확인할 수 있습니다. 

 

 이제 useEffect 훅을 사용하여 페이지가 리렌더링 될 때 제목 입력창을 focus합니다. 

 

  useEffect(()=>{
    titleInput.current.focus();
  }, [])

 

 제목을 입력한 뒤 엔터키를 누르면 본문 입력 창에 focus를 가도록 하기 위해, onKeyUp 이벤트 콜백함수를 작성합니다.

 

  const onKeyUp = (e) => {
    if(e.key === 'Enter'){
      contentsInput.current.focus();
    }
  }

 

 

 

 

[ 예제2 - 사용자 이름 입력받기 ]

// App.jsx
import React, { useState, useEffect, useRef, useMemo } from 'react';
import UserList from './UserList';
import AddUser from './AddUser';

const users = [
  {
    id: 1,
    name: 'neo'
  },
  {
    id: 2,
    name: 'lion'
  }
]

const App = () => {
  const [data, setData] = useState(users)
  const [name, setName] = useState('')
  const userID = useRef(3);
  const nameInput = useRef();
  

  const onChange = (e) => {
    const { value } = e.target;
    setName(value);
  }

  const onSubmit = () => {
    console.log('submit!')
    const newUser = {
      id: userID.current,
      name: name
    }

    console.log(newUser)
    setData([...data, newUser]);
    setName('');
    nameInput.current.focus();
    userID.current += 1;
  }
  useMemo(()=>{console.log('data', data)}, [data]);
  
  return (
    <div>
      <AddUser name={name} onChange={onChange} nameInput={nameInput} onSubmit={onSubmit} />
      <UserList users={data} />
    </div>
  );
};

export default App;
// AddUser.jsx
import React, { useEffect } from 'react';

const AddUser = ({name, onChange, nameInput, onSubmit}) => {

  useEffect(()=>{
    nameInput.current.focus();
  }, []);

  return (
    <>
      <input type="text"
        name="name"
        value={name}
        onChange={onChange}
        ref={nameInput}
         />
      <button type="button" onClick={onSubmit}>작성</button>
    </>
  );
};

export default AddUser;
// UserList.jsx
import React from 'react';

const UserList = ({ users }) => {
  return (
    <div>
      {users.map((user) => (
        <p key={user.id}>id: {user.id} | 이름: {user.name} </p>
      ))}
    </div>
  );
};

export default UserList;
반응형