![notion image](https://www.notion.so/image/https%3A%2F%2Fs3.us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F14f19757-859b-468e-85ab-4ef13d7a0fd7%2FUntitled.png%3FX-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Credential%3DAKIAT73L2G45O3KS52Y5%252F20211025%252Fus-west-2%252Fs3%252Faws4_request%26X-Amz-Date%3D20211025T151946Z%26X-Amz-Expires%3D86400%26X-Amz-Signature%3D234ff8a1b3a4114e40c8c73e51703f17baafe05bf7716dea426c85866026a8c8%26X-Amz-SignedHeaders%3Dhost?table=block&id=17ad5ca9-589c-4b42-86de-cc348085680a&cache=v2)
(์ฐธ๊ณ ํ ์ฝ๋)
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3.us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F107e7cf4-8f7e-44c1-a9c5-a4f958d1a0d3%2FUntitled.png%3FX-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Credential%3DAKIAT73L2G45O3KS52Y5%252F20211025%252Fus-west-2%252Fs3%252Faws4_request%26X-Amz-Date%3D20211025T151946Z%26X-Amz-Expires%3D86400%26X-Amz-Signature%3D6575da6362600f0cd987394ec96e9f041060423df160be31080b6717fb09a671%26X-Amz-SignedHeaders%3Dhost?table=block&id=beae3d6b-9c37-411a-a2fc-1e6094f08855&cache=v2)
autocomplete searchBar๋ฅผ ๊ตฌํํ๋ ์ค์ ํ์ด์ง์ ๋ค์ด๊ฐ์ ๋ auto focusing๋๋ ๊ฒ์ ๊ตฌํํด๋ณด๋ ค๊ณ ํ๋ค. useRef๋ฅผ ์ฌ์ฉํด์ input ์๋ฆฌ๋จผํธ์ ref๋ฅผ ์ก์์ focus()๋ฅผ ํธ์ถํด์ฃผ๋ ค๊ณ ํ์ง๋ง ํ์
์คํฌ๋ฆฝํธ๋ฅผ ์ ์ฉํ ๋ฆฌ์กํธ ํ๋ก์ ํธ์ฌ์ ์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
ย
DOM ์์๊ฐ ๋ง์ดํธ๋ ์ดํ์ focus()์ํค๋ ค๊ณ ํ์ง๋ง useRef(null)์ ํ ๋นํ๋ฉด ๊ฐ์ฒด searchBarRef๊ฐ null์ด ๋ ์ํ์์ useEffect()๊ฐ ํธ์ถ๋๋ ์์์ด๋ค. ์ค์ ๋ก ๊ทธ๋ ๊ฒ ๋์ํ์ง ์์ง๋ง. ์ฝ๋ ์์๋ ๊ทธ๋ ๋ค.
๋ฐ์์ return ๋ฉ์๋ ๋ด์ DOM ์์๋ค์ด ๋ถ๋ฌ์ง๊ณ ๋์ useEffect๋ ํธ์ถ๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ ์๋์ ๊ธ์์๋ ์ด๊ฒ๋ง ์์ฑํด๋ ์ ๋์ํ๋ค๊ณ ํ์ง๋ง ํ์
์คํฌ๋ฆฝํธ๋ ์๋ฌ๋ฅผ ๋ณด์ฌ์คฌ๋ค.
ํ์
์ ๋ง์ถฐ์ฃผ๋ ค๊ณ useRef์ HTMLInputElement๋ฅผ ์ฃผ๊ณ ๋ด๋ถ์์ ์กฐ๊ฑด๋ฌธ์ผ๋ก ์ฒดํฌ๋ ํด์ฃผ์๋ค. (์๋๋ฉด if๋ฌธ์ผ๋ก null์ ๊ฒ์ฌํ ๊ฒ์ ์ต์
๋ ์ฐ์ฐ์ ?๋ก searchBarRef.current?.focus()๋ก ์ฒดํฌํด์ค ์ ์๋ค.)
const searchBarRef = React.useRef<HTMLInputElement>(null);
React.useEffect(() => {
ย
์ด๋ ๊ฒ ๊ตฌํ์ ํ๋ค๊ฐ ์ฌ๋ฌ ๋ฒ ์ฌ์ฉ๋ ๊ฒ์ผ๋ก ์๊ฐ๋์ auto focus๋ฅผ ํด์ค ์ ์๋ ์ปค์คํ
ํ
์ ๋ง๋ค์ด์ผ๊ฒ ๋ค๋ ์๊ฐ์ด ๋ค์๋ค. ์ด๋ฏธ ์ ๋ง๋ค์ด์ง ๊ฒ๋ค์ด ์๊ฒ ์ง๋ง ํผ์ ๊ตฌํํด๋ณด๋ฉด์ ์ดํดํ๋ ๊ฒ์ด ๋์์ด ๋ ๊ฒ ๊ฐ์๋ค.
useAutofocus hook์ ๋ง๋ค์๋๋ ์ฌ์ฉํ๋ ๊ณณ์์ ์๋ฌ๋ฅผ ๋๋ค. ์๋ํ๋ฉด ๊ณต์ฉ์ผ๋ก ์ฌ์ฉํด์ผ ํด์ useRef<HTMLElement>๋ก type scope๋ฅผ ๋ํ์ ์ง์ ํด๋์๊ธฐ ๋๋ฌธ์ด๋ค.
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3.us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F6d33c713-f4bd-4f59-8c37-88f916479813%2FUntitled.png%3FX-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Credential%3DAKIAT73L2G45O3KS52Y5%252F20211025%252Fus-west-2%252Fs3%252Faws4_request%26X-Amz-Date%3D20211025T151946Z%26X-Amz-Expires%3D86400%26X-Amz-Signature%3D9933e5257a83c1d72fe0555131682ede6344295bdda0db0945fe8db5954c7626%26X-Amz-SignedHeaders%3Dhost?table=block&id=8712f1bc-2551-47c9-8e3f-add8ca7556e2&cache=v2)
RefObject<HTMLElement> is not assignable to type 'LegacyRef<HTMLInputElement> | undefined.
ย
์ด๊ฑธ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ 2๊ฐ์ง๊ฐ ์๋ค.
(ํ์
์คํฌ๋ฆฝํธ ํธ๋๋ถ์ ์ฐธ๊ณ ํ๋ค. https://joshua1988.github.io/)
์ฒซ๋ฒ์งธ๋ as๋ฅผ ์ฌ์ฉํด์ ๊ตฌ์ฒด์ ์ผ๋ก ํ์
์ ์ง์ ํด์ฃผ์ด์ผ ํ๋๋ฐ ์ด๊ฒ์ ํ์
๋จ์ธ(Type Assertion)์ด๋ผ ํ๋ค.
ํ์ ๋จ์ธ(Type Assertion)
ํ์
๋จ์ ์ ๊ฐ๋ฐ์๊ฐ ํด๋น ํ์
์ ๋ํด ํ์ ์ด ์์ ๋ ์ฌ์ฉํ๋ ํ์
์ง์ ๋ฐฉ์์
๋๋ค. ๋ค๋ฅธ ์ธ์ด์ ํ์
์บ์คํ
๊ณผ ๋น์ทํ ๊ฐ๋
์ด๋ฉฐ ํ์
์คํฌ๋ฆฝํธ์์ ํน๋ณํ ํ์
์ ์ฒดํฌํ์ง ์๊ณ , ๋ฐ์ดํฐ์ ๊ตฌ์กฐ๋ ์ ๊ฒฝ์ฐ์ง ์์ต๋๋ค.(ํ์
์คํฌ๋ฆฝํธ ํธ๋๋ถ)
import React from "react";
export function useAutofocus() {
const ref = React.useRef(null);
React.useEffect(() => {
ref.current?.focus();
}, [ref]);
return ref;
}
// searchBar.tsx
const searchBarRef = useAutofocus();
...
<input
ref={searchBarRef as React.RefObject<HTMLDivElement>}
...
/>
์ด๋ ๊ฒ ํ๋ฉด ์ฌ์ฉํ ๋๋ง๋ค ํ์
๋จ์ธ์ผ๋ก ์ ์ ์๋ํ๊ฒ ๋ง๋ค ์ ์์ง๋ง ํ์
์คํฌ๋ฆฝํธ๋ ์ด๋ด ๋ ์ฌ์ฉํ ์ ์๋ ๊ฐ๋
์ ์ด๋ฏธ ๊ฐ์ง๊ณ ์๋ค. ๊ทธ๊ฒ ๋๋ฒ์งธ๋ค.
ย
๋๋ฒ์งธ๋ก๋ ์ ๋ค๋ฆญ(Generics)์ ์ฌ์ฉํ๋ ๋ฐฉ์์ด ์๋ค.
์ ๋ค๋ฆญ(Generics)์ ์ฌ์ ์ ์ ์
์ ๋ค๋ฆญ์ C#, Java ๋ฑ์ ์ธ์ด์์ ์ฌ์ฌ์ฉ์ฑ์ด ๋์ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ๋ ์์ฃผ ํ์ฉ๋๋ ํน์ง์
๋๋ค. ํนํ, ํ๊ฐ์ง ํ์
๋ณด๋ค ์ฌ๋ฌ ๊ฐ์ง ํ์
์์ ๋์ํ๋ ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ๋๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
์ ๋ค๋ฆญ์ด๋ ํ์
์ ๋ง์น ํจ์์ ํ๋ผ๋ฏธํฐ์ฒ๋ผ ์ฌ์ฉํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
๊ธฐ๋ณธ์ ์ธ ์์ ๋ ์๋์ ๊ฐ๋ค.
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3.us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fb9a2777f-5caf-4b5b-92ab-25abe4d82ab7%2FUntitled.png%3FX-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Credential%3DAKIAT73L2G45O3KS52Y5%252F20211025%252Fus-west-2%252Fs3%252Faws4_request%26X-Amz-Date%3D20211025T151946Z%26X-Amz-Expires%3D86400%26X-Amz-Signature%3Df6c2018de32fb4ef89bb43687afa23c1d5255494b35bb71003ff5ed990aa6047%26X-Amz-SignedHeaders%3Dhost?table=block&id=541f9325-b449-452d-8069-20dd031759a2&cache=v2)
ย
์ ๋ค๋ฆญ ํ์
์ ์ ์ฉํ๋ฉด HTMLElementํ์
์ ํฌํจ๋๋ T๋ก ๋ฐ์ ์ปค์คํ
ํ
์ ๊ตฌ์ฑ์ํฌ ์ ์๋ค.
์ด ๊ฒฝ์ฐ ์๋ฌ๊ฐ ์ฌ๋ผ์ง๊ฒ ๋๋ค.
const searchBarRef = useAutofocus<HTMLInputElement>();
...
<input
ref={searchBarRef}
/>
...
// useAutofocus()
import React from "react";
export function useAutofocus<T extends HTMLElement>() {
const ref = React.useRef<T>(null);
React.useEffect(() => {
ref.current?.focus();
}, [ref]);
return ref;
}
๋ฆฌ์กํธ์ ํ์
์คํฌ๋ฆฝํธ ๊ตฌ์กฐ๋ฅผ ์์ฃผ ์ฌ์ฉํ๊ณ ์๋๋ฐ ์ด๋ฒ ์๋ฌ๋ฅผ ํด๊ฒฐํ๋ฉด์ ํ์
์คํฌ๋ฆฝํธ ํธ๋๋ถ์ ์ข
์ข
๋ด์ผํ๋ค๋ ์๊ฐ๊ณผ ์ดํํฐ๋ธ ํ์
์คํฌ๋ฆฝํธ๊ฐ ์ ๋ช
ํ๋๋ฐ ๊ทธ ์ฑ
์ ์ฌ์ ๊ณต๋ถํด๋ณผ๊น ์ถ์๋ค. ์ต๊ทผ ๋ค์ด ๊ธฐ๋ณธ๊ธฐ๋ฅผ ๋ค์ง๊ธฐ ์ํด์ ๋ฐ๋๋ผ ์๋ฐ์คํฌ๋ฆฝํธ ์์ฃผ๋ก ๊ณต๋ถํด์ ํท๊ฐ๋ฆฌ๋ ๋ถ๋ถ๋ค์ด ์์๋๋ฐ ์ญ์ ๊พธ์คํ ๊ณต๋ถํด์ผ ํ๋ค.
ย