본문 바로가기
개발/React

리액트 - useRef로 특정 위치로 포커스 이동하기 (Use Ref Hook Focus)

by 피로물든딸기 2023. 6. 17.
반응형

리액트 전체 링크

 

focus test 버튼을 누르면 input으로 이동해서 포커싱이 되도록 해보자.

아래의 코드로 시작한다.

import { useState, useEffect } from "react";

function App() {
  const [temp, setTemp] = useState([]);

  useEffect(() => {
    let t = [];
    for (let i = 0; i < 100; i++) t.push(i);
    setTemp(t);
  }, []);

  return (
    <div className="App">
      <button>focus test</button>

      {temp.map((item, idx) => (
        <p key={idx}>{item}번째 p tag</p>
      ))}
      <input type="text"/>
    </div>
  );
}

export default App;

 

focus test 버튼을 누르면 맨 아래의 input으로 이동하도록 해보자.


useRef 선언

 

focus 기능을 사용하기 위해서는 useRef를 이용한다.

import { useState, useEffect, useRef } from "react";

function App() {
  const focusTest = useRef(null);

 

만든 useRef인  focusTest를 inputref에 설정하자.

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

 

이제 버튼을 누르면 아래의 input으로 이동한다.

 

전체 코드는 다음과 같다.

import { useState, useEffect, useRef } from "react";

function App() {
  const focusTest = useRef(null);
  
  const [temp, setTemp] = useState([]);

  useEffect(() => {
    let t = [];
    for (let i = 0; i < 100; i++) t.push(i);
    setTemp(t);
  }, []);


  return (
    <div className="App">
      <button onClick={() => focusTest.current.focus()}>focus test</button>

      {temp.map((item, idx) => (
        <p key={idx}>{item}번째 p tag</p>
      ))}
      <input type="text"></input>
    </div>
  );
}

export default App;

여러 개의 useRef

 

여러 input으로 이동하려면 useRef를 더 선언하면 된다.

예를 들면 아래와 같다.

import { useState, useEffect, useRef } from "react";

function App() {
  const focusTest = useRef(null);
  const focusTest2 = useRef(null);
  const focusTest3 = useRef(null);
  
  const [temp, setTemp] = useState([]);

  useEffect(() => {
    let t = [];
    for (let i = 0; i < 100; i++) t.push(i);
    setTemp(t);
  }, []);


  return (
    <div className="App">
      <button onClick={() => focusTest.current.focus()}>focus test</button>
      <button onClick={() => focusTest2.current.focus()}>focus test2</button>
      <button onClick={() => focusTest3.current.focus()}>focus test3</button>

      {temp.map((item, idx) => (
        <p key={idx}>{item}번째 p tag</p>
      ))}
      <input type="text" ref={focusTest}></input>
      <input type="text" ref={focusTest2}></input>
      <input type="text" ref={focusTest3}></input>
      

    </div>
  );
}

export default App;

 

위의 코드라면 focus test3 버튼을 누르면 번째 input으로 이동한다.

 

하지만 더 간결하게 하려면 useRef배열로 선언하면 된다.

const focusTest = useRef([]);

 

inputref는 아래와 같이 코드가 변경된다.

      <input type="text" ref={(val) => (focusTest.current[0] = val)}></input>
      <input type="text" ref={(val) => (focusTest.current[1] = val)}></input>
      <input type="text" ref={(val) => (focusTest.current[2] = val)}></input>

 

focus()를 호출하는 부분은 아래와 같이 변하게 된다.

      <button onClick={() => focusTest.current[0].focus()}>focus test</button>
      <button onClick={() => focusTest.current[1].focus()}>focus test2</button>
      <button onClick={() => focusTest.current[2].focus()}>focus test3</button>

 

전체 코드는 다음과 같다.

import { useState, useEffect, useRef } from "react";

function App() {
  const focusTest = useRef([]);

  const [temp, setTemp] = useState([]);

  useEffect(() => {
    let t = [];
    for (let i = 0; i < 100; i++) t.push(i);
    setTemp(t);
  }, []);

  return (
    <div className="App">
      <button onClick={() => focusTest.current[0].focus()}>focus test</button>
      <button onClick={() => focusTest.current[1].focus()}>focus test2</button>
      <button onClick={() => focusTest.current[2].focus()}>focus test3</button>

      {temp.map((item, idx) => (
        <p key={idx}>{item}번째 p tag</p>
      ))}
      <input type="text" ref={(val) => (focusTest.current[0] = val)}></input>
      <input type="text" ref={(val) => (focusTest.current[1] = val)}></input>
      <input type="text" ref={(val) => (focusTest.current[2] = val)}></input>
    </div>
  );
}

export default App;


<p> 태그에 포커스 맞추기 (tabIndex)

 

먼저 아래와 같이 코드를 수정해서 N번째 p 태그로 이동하도록 해보자.

input에 입력받은 태그로 이동하도록 useStateinput + button을 추가하였다.

import { useState, useEffect, useRef } from "react";

function App() {
  const focusTest = useRef([]);
  const pTagFocus = useRef([]); /* <p> 태그 포커스 용 useRef */

  const [temp, setTemp] = useState([]);
  const [number, setNumber] = useState("");

  useEffect(() => {
    let t = [];
    for (let i = 0; i < 100; i++) t.push(i);
    setTemp(t);
  }, []);

  return (
    <div className="App">
      <input value={number} onChange={(e) => setNumber(e.target.value)} />
      <button
        onClick={() => {
          pTagFocus.current[number].focus();
        }}
      >
        번째 p 태그로 이동
      </button>
      <button onClick={() => focusTest.current[0].focus()}>focus test</button>
      <button onClick={() => focusTest.current[1].focus()}>focus test2</button>
      <button onClick={() => focusTest.current[2].focus()}>focus test3</button>

      {temp.map((item, idx) => (
        <p
          key={idx}
          ref={(val) => (pTagFocus.current[idx] = val)}
        >
          {item}번째 p tag
        </p>
      ))}
      <input type="text" ref={(val) => (focusTest.current[0] = val)}></input>
      <input type="text" ref={(val) => (focusTest.current[1] = val)}></input>
      <input type="text" ref={(val) => (focusTest.current[2] = val)}></input>
    </div>
  );
}

export default App;

 

그런데 버튼을 눌러도 아무 반응이 없다.

 

포커스가 가능한 태그는 여러 개가 있는데, 대표적으로 input, button, textarea 등이다.

그 외 <p> 태그<div> 태그등은 포커스가 불가능하다.

 

위의 태그도 포커싱이 되려면 tabIndex를 설정하면 된다.

        <p
          key={idx}
          ref={(val) => (pTagFocus.current[idx] = val)}
          tabIndex={idx}
        >
          {item}번째 p tag
        </p>

 

이제 <p> 태그로도 정상적으로 포커싱이 된다.

 

전체 코드는 다음과 같다.

import { useState, useEffect, useRef } from "react";

function App() {
  const focusTest = useRef([]);
  const pTagFocus = useRef([]); /* <p> 태그 포커스 용 useRef */

  const [temp, setTemp] = useState([]);
  const [number, setNumber] = useState("");

  useEffect(() => {
    let t = [];
    for (let i = 0; i < 100; i++) t.push(i);
    setTemp(t);
  }, []);

  return (
    <div className="App">
      <input value={number} onChange={(e) => setNumber(e.target.value)} />
      <button
        onClick={() => {
          pTagFocus.current[number].focus();
        }}
      >
        번째 p 태그로 이동
      </button>
      <button onClick={() => focusTest.current[0].focus()}>focus test</button>
      <button onClick={() => focusTest.current[1].focus()}>focus test2</button>
      <button onClick={() => focusTest.current[2].focus()}>focus test3</button>

      {temp.map((item, idx) => (
        <p
          key={idx}
          ref={(val) => (pTagFocus.current[idx] = val)}
          tabIndex={idx}
        >
          {item}번째 p tag
        </p>
      ))}
      <input type="text" ref={(val) => (focusTest.current[0] = val)}></input>
      <input type="text" ref={(val) => (focusTest.current[1] = val)}></input>
      <input type="text" ref={(val) => (focusTest.current[2] = val)}></input>
    </div>
  );
}

export default App;
반응형

댓글