useRef hook를 배웠다. 과제를 하던중 여러 input창에 모두 useRef를 이용하여 같은 기능을 구현하고싶은데 각각 따로따로 써야하나 의문이 들고 찾아본 결과를 정리해보겠다!
렌더링에 필요하지 않은 값을 참조할 수 있는 React Hook이다. 따라서 용도는 1. 정보 저장 2. DOM 조작 이다.
const inputWriterRef = useRef();
const inputTitleRef = useRef();
const inputSearchRef = useRef();
<input ref = {inputWriterRef}/>;
<input ref = {inputTitleRef}/>;
<input ref = {inputSearchRef}/>;
inputWriterRef.current.focus();
inputTitleRef.current.focus();
inputSearchRef.current.focus();
방법이 2가지가 있다.
1. 객체 사용
: 명확한 이름으로 참조를 관리해야 하거나, 각 참조가 특정한 의미를 갖는 경우 유리
2. 배열 사용
: 동일한 유형의 여러 참조를 관리하거나, 참조가 순차적으로 추가되는 경우 유리(반복적인 UI 요소)
이번 상황에서는 명확한 이름으로 관리하는게 적절하다 생각되어 객체를 사용하였다.
const refs = useRef({
writer: null,
title: null,
searchText: null,
});
ref={(el) => (refs.current.writer = el)}
if (writer.trim().length === 0) {
refs.current.writer.focus();
return;
}
import React, { useRef, useState } from "react";
function Practice() {
const [text, setText] = useState([]);
const [writer, setWriter] = useState("");
const [title, setTitle] = useState("");
const [searchOption, setSearchOption] = useState("writer");
const [searchText, setSearchText] = useState("");
const [filteredText, setFilteredText] = useState([]);
// 객체를 사용하여 useRef 생성
const refs = useRef({
writer: null,
title: null,
searchText: null,
});
// 데이터 추가
const addText = (e) => {
e.preventDefault();
const newText = text.concat({
id: text.length + 1,
writer: writer,
title: title,
});
if (writer.trim().length === 0) {
refs.current.writer.focus();
return;
}
if (title.trim().length === 0) {
refs.current.title.focus();
return;
}
setText(newText);
setWriter("");
setTitle("");
};
// 검색 기능
const handleSearch = () => {
if (searchText.trim().length === 0) {
// setFilteredText([]);
refs.current.searchText.focus();
return;
}
const filtered = text.filter((info) => {
if (searchOption === "writer") {
return info.writer.includes(searchText);
} else if (searchOption === "title") {
return info.title.includes(searchText);
}
return false;
});
setFilteredText(filtered);
setSearchText("");
};
// 전체 검색
const handleSearchAll = () => {
setFilteredText(text);
};
// 키보드 이벤트
const handleKeyDown = (e, action) => {
if (e.keyCode === 13) {
action(e);
}
};
return (
<>
<form style={{ margin: "10px" }}>
작성자:
<input
type="text"
placeholder="작성자"
value={writer}
onChange={(e) => setWriter(e.target.value)}
ref={(el) => (refs.current.writer = el)}
/>
제목:
<input
type="text"
placeholder="제목"
value={title}
onChange={(e) => setTitle(e.target.value)}
onKeyDown={(e) => handleKeyDown(e, addText)}
ref={(el) => (refs.current.title = el)}
/>
<button onClick={addText}>작성</button> <br />
</form>
<div style={{ margin: "10px" }}>
<select
value={searchOption}
onChange={(e) => setSearchOption(e.target.value)}
>
<option value="writer">작성자</option>
<option value="title">제목</option>
</select>
<input
type="text"
placeholder="검색어를 입력하세요."
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
onKeyDown={(e) => handleKeyDown(e, handleSearch)}
ref={(el) => (refs.current.searchText = el)}
/>
<button onClick={handleSearch}>검색</button>
<button onClick={handleSearchAll}>전체</button>
</div>
<table
border="1"
cellPadding="10"
cellSpacing="1"
style={{ margin: "10px" }}
>
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
</tr>
</thead>
<tbody>
{text.map((value) => (
<tr key={value.id}>
<td>{value.id}</td>
<td>{value.title}</td>
<td>{value.writer}</td>
</tr>
))}
</tbody>
</table>
{filteredText.length > 0 ? (
<p>검색 결과</p>
) : (
<p>검색 결과가 없습니다.</p>
)}
{filteredText.length > 0 && (
<table
border="1"
cellPadding="10"
cellSpacing="1"
style={{ margin: "10px" }}
>
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
</tr>
</thead>
<tbody>
{filteredText.map((value) => (
<tr key={value.id}>
<td>{value.id}</td>
<td>{value.title}</td>
<td>{value.writer}</td>
</tr>
))}
</tbody>
</table>
)}
</>
);
}
export default Practice;
리액트의 useRef hook에 대해 학습하였다. 용도를 알게 되었고 어떻게 하면 더 효율적으로 쓸 수 있을까 고민하는 시간이 되었다. 리액트에는 많은 hook이 존재한다고 하는데 차근히 배워보고 익혀야겠다.
출처 및 참고
1. [새싹 X 코딩온] 영등포 캠퍼스 6기 입문자도 가능한 웹 개발자 부트캠프 강의 교안
2. https://ko.react.dev/reference/react/useRef
3. https://velog.io/@minho100227/useRef%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-focus%EA%B8%B0%EB%8A%A5