๐ React Native ๋ฆฌ์กํธ ๋ค์ดํฐ๋ธ - Hook
๐ซ ๋ฆฌ์กํธ ํ - React Hooks
@ U ์ค๊ฐ๊ณ ์ฌ ์ถ์ : ๋ฆฌ์กํธ ํ & ์ํ ๊ฐ๋
React ํ๋ ์์ํฌ,
์ปดํฌ๋ํธ ๊ธฐ๋ฒ์ผ๋ก ๊ฐ์ DOM ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ๋์,
๊ฐ์ DOM ๊ฐ์ฒด์ ์ด๋ค ๋ณํ๊ฐ ๊ฐ์ง๋๋ฉด, ํด๋น ๋ณํ๋ง ์ฌ๋ ๋๋งํ์ฌ ์ ์ฒด ๋ ๋๋ง ์๋๋ฅผ ๋น ๋ฅด๊ฒ
Old
๊ฐ์ฒด ์งํฅ ์ธ์ด์ ์์ ๊ฐ๋
์ ๋ง์ถ, ํด๋์ค ํํ๋ก ์ ์๋์์
โ ํด๋์ค ์ปดํฌ๋ํธ ๊ธฐ์ โ ์ฝ๋ ์์ฑ ๋ณต์ก
โ 60/1s ๊ฐ์ ๋น ๋ฅธ ์ฌ๋ ๋๋ง ์ ์ ์์ ์ธ ๋ ๋๋ง์ด ์๋๋ ๋ฒ๊ทธ
New
๊ตฌํ ๋ณต์กํจ์ ๋์ด๋ด๊ณ ์ ์ปดํฌ๋ํธ๋ฅผ ํจ์ ํํ๋ก ๋ง๋ค ์ ์๋๋ก
ํจ์ ์ปดํฌ๋ํธ๊ฐ ์ด๋ค ๊ฐ์ Persistence - ์ ์ง ํ ์ ์๋๋ก, New ๋ฐ์ดํฐ Cache ์์คํ
Cache ์์คํ
์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก use~ ๋ก ์์ํ๋ ์ฌ๋ฌ API
์ ๊ณต
โ React Hooks - ๋ฆฌ์กํธ ํ
์ฆ, ํจ์ ๋ด ๋ก์ปฌ๋ณ์๋ฅผ ํด๋์ค์ ์ ์ญ๋ณ์์ฒ๋ผ ์ฌ์ฉํ๊ธฐ ์ํด
๋ก์ปฌ๋ณ์๊ฐ ์ค์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง์ง ์๊ณ ,
์ค์ ๋ฐ์ดํฐ๋ ์ด๋์ธ๊ฐ ์บ์ํ๊ณ ์
๋ก์ปฌ๋ณ์๋ ํ์ํ ๋ ์บ์ํ ๋ฐ์ดํฐ๋ฅผ ์ฐพ์ ์ ์๋ ์ผ์ข
์ ํค๋ฅผ ์ ์ฅํ๋ ๋ฐฉ๋ฒ์ ๊ณ ์ โ Reference
@ ํฌ์ธํฐ, ์ฐธ์กฐํ์ ์ ์ฌํ ๊ฐ๋ ์ธ๋ฏ?
์๋ ์ฌ์ฉ์๊ฐ ์ง์ ๊ตฌํํด ์ฌ์ฉํ์ง๋ง,
๋ฆฌ์กํธ์์ ์ ๊ณตํ useMemo ํ
์ ํตํด ์ฌ์ฉ
โ ์๋๋ ๊ธฐ์กด ๊ตฌํ ๋ฐฉ๋ฒ
const cache: Record<string, any> = {}
export const createOrUse = <T>(key: string, callback: () => T) =>
{
if (!cache[key])
cache[key] = callback()
return cache[key]
}
const temp = createOrUse('Temp', () => createTemp)
/*
Record<Key, Type>
TypeScript์์ ์ ๊ณตํ๋ ๊ฐ์ฒด ํ์
Type์ ์๋ฌด ํ์
์ด๋ ์ฌ ์ ์์
์์ผ๋ฉด ๊บผ๋ด์ ๋ฐํ
์์ผ๋ฉด callback์ผ๋ก ์ด๊ธฐํ ํ ๋ฐํ
*/
i.e.
์ปดํฌ๋ํธ ๋ฐ์ดํฐ ๊ด๋ฆฌ - useMemo, useCallback, useState, useReducer
์ปดํฌ๋ํธ ์๋ช
์ฃผ๊ธฐ ๋์ - useEffect, useLayoutEffect
์ปดํฌ๋ํธ ๊ฐ์ ์ ๋ณด ๊ณต์ - useContext
์ปดํฌ๋ํธ ๋ฉ์๋ ํธ์ถ - useRef, useImperativeHandle
๐ซ ์์กด์ฑ - Dependency
์บ์๋ฅผ ๊ฐฑ์ ํด์ผํ๋ ํน์ ์กฐ๊ฑด/์ํฉ๋ค
์์กด์ฑ ๋ชฉ๋ก
์ค ํ๋๋ผ๋ ์ถฉ์กฑ๋๋ฉด,
์๋์ผ๋ก ์บ์ ๊ฐฑ์ (์ฝ๋ฐฑ) โ ์ฌ๋ ๋๋ง
๐ซ useMemo
@ U ๊ธฐ๋ง๊ณ ์ฌ ์ถ์ : useMemo
1
2
3
4
const ์บ์๋_๋ฐ์ดํฐ = useMemo(์ด๊ธฐ๊ฐ, [์์กด์ฑ1, ์์กด์ฑ2, ...])
const ์บ์๋_๋ฐ์ดํฐ = useMemo(์ฝ๋ฐฑ, [์์กด์ฑ1, ์์กด์ฑ2, ...])
์ฝ๋ฐฑ = () => ์ด๊ธฐ๊ฐ
๊ฐ(, ํจ์)์ ๋ฉ๋ชจ์ด์ ์ด์
โ ํจ์ : () => ์ฝ๋ฐฑ
useCallback์ด ์๋๋ฐ, useMemo๋ก ํจ์๋ฅผ ๋ฉ๋ชจ์ด์ ์ด์
ํ๋ ๊ฒฝ์ฐ?
โ useMemo๋ฅผ ์ฐ๋ฉด ํจ์์ ๊ทธ ๊ฒฐ๊ณผ ๊ฐ
์ ํจ๊ป ๋ฉ๋ชจ์ด์ ์ด์
@ 222p, useMemo(() => fibonacci, [])...
๋์ผํ ์
๋ ฅ๊ฐ์ ๋ํด ํจ์๊ฐ ๋ฐ๋ณตํด์ ํธ์ถ๋๋ ๊ฒ์ ๋ฐฉ์ง (๊ธฐ๋ง๊ณ ์ฌ X)
๐ซ useCallback
@ U ๊ธฐ๋ง๊ณ ์ฌ ์ถ์ : useCallback
1
const ์บ์์ฝ๋ฐฑ = useCallback(์ด๊ธฐ์ฝ๋ฐฑ, [์์กด์ฑ1, ์์กด์ฑ2, ...])
ํจ์๋ฅผ ๋ฉ๋ชจ์ด์ ์ด์
์ฌ๋ ๋๋ง๋ง๋ค ์ง์์ ์ผ๋ก ๋ง๋ค์ด์ง ์ ์๋ ์ฝ๋ฐฑ ํจ์๋ฅผ, useCallback์ ํตํด ์ ์ฅํด์ ์ฌ์ฌ์ฉ
๐ซ ์ํ
@ U ์ค๊ฐ๊ณ ์ฌ ์ถ์ : ๋ฆฌ์กํธ ํ & ์ํ ๊ฐ๋
์๊ฐ์ด ์ง๋๋ ๊ฐ์ด ์ ์ง๋๋ฉฐ, ํ์์ ๋ฐ๋ผ์๋ ๊ฐ์ ๋ฐ๊ฟ ์ ์๋ ์ด๋ค ๊ฒ
ํด๋์ค์ ๋ฉค๋ฒ ์์ฑ์ด๋ ์ ์ญ ๋ณ์ ํํ๋ก ๋ง๋ค๊ฒ ๋๋ฉฐ, ๋ณดํต ํจ์ ๋ชธํต์ ์ง์ญ ๋ณ์ ํํ๋ก๋ ์ํ๋ฅผ ๋ง๋ค์ง ๋ชปํจ
๐ซ useState
@ U ์ค๊ฐ๊ณ ์ฌ ์ถ์ : ๋ฆฌ์กํธ ํ
& ์ํ ๊ฐ๋
@ U ๊ธฐ๋ง๊ณ ์ฌ ์ถ์ : useState
1
2
3
4
5
6
7
8
9
10
import React, {useState} from 'react'
{ /* ํ์
์ ์, S - State Type */ }
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>]
{ /* ์ฌ์ฉ ๋ฐฉ๋ฒ */ }
const [๊ฐ, Setter] = useState(์ด๊น๊ฐ)
const [๊ฐ, Setter] = useState<S>(์ด๊น๊ฐ)
{ /* ๊ฐ์ ๋ณ๊ฒฝํ๋ ํจ์ (Setter)๋ฅผ ํธ์ถํ๋ฉด ๊ฐ ๋ถ๋ถ์ ๋ณ๊ฒฝํ๊ณ , ์ปดํฌ๋ํธ๋ฅผ ์ฌ๋ ๋๋ง */}
{ /* ์ฌ๋ ๋๋ง ๋๋ฌธ์ useState ํ
์ ๊ฐ๊ณผ Setter ํจ์๋ฅผ Tuple ํํ์ ๋ฐฐ์ด๋ก ๋ฐํ */}
ํจ์ ์ปดํฌ๋ํธ ๋ด๋ถ์ ํด๋์ค์ ๋ฉค๋ฒ ์์ฑ์ฒ๋ผ ๊ฐ์ ์ ์งํ๊ณ ๋ณ๊ฒฝํ ์ ์๋ ์ํ๋ฅผ ๋ง๋ค ์ ์๊ฒ ํ๋ค
์ํ ์ ์ฅ (์ง์ญ๋ณ์๋ฅผ ์ ์ญ๋ณ์์ฒ๋ผ)
@ ๋ฐฐ์ด์ ์ ์ฉํ๋ ๋น๊ตฌ์กฐํ ํ ๋น ๊ตฌ๋ฌธ
ํ ๋น ๋ฐ๋ ๋ณ์ ์ด๋ฆ์ ์์ ๋กญ๊ฒ
@ ๊ฐ์ฒด์ ์ ์ฉํ๋ ๋น๊ตฌ์กฐํ ํ ๋น ๊ตฌ๋ฌธ
๐ซ ์ปดํฌ๋ํธ์ ์๋ช ์ฃผ๊ธฐ
์ปดํฌ๋ํธ๋ฅผ ์์ฑํ์ฌ ์ต์ด ๋ ๋๋ง ๊ณผ์ ์ ๋๋ง์นจ : ์ปดํฌ๋ํธ๋ฅผ ๋ง์ดํธํ๋ค. - Mount
๋ง์ดํธ๋ ์ปดํฌ๋ํธ๋ ๊ตฌํ ๋ก์ง์ ๋ฐ๋ผ ์ฌ๋ ๋๋ง์ ๊ฑฐ๋ญํ๋ค, ์ด๋ค ์์ ์์ ๊ตฌํ ๋ก์ง์ ์ํด ํ๊ดด๋์ด ์ฌ๋ผ์ง
์ปดํฌ๋ํธ๊ฐ ํ๊ดด๋์ด ๋๋ ๋ ๋๋ง ๊ณผ์ ์ ์ฐธ์ฌํ์ง ์์ : ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ๋๋ค. - Unmount
๋ง์ดํธ ~ ์ธ๋ง์ดํธ ๊ณผ์ ์ ํฉํ์ฌ, ์ปดํฌ๋ํธ์ ์๋ช ์ฃผ๊ธฐ๋ผ ํํํ๋ค. - Lifecycle
๐ซ useEffect, useLayoutEffect
@ U ์ค๊ฐ๊ณ ์ฌ ์ถ์ : useEffect
@ U ๊ธฐ๋ง๊ณ ์ฌ ์ถ์ : useEffect (setInterval?)
์ปดํฌ๋ํธ์ ์๋ช
์ฃผ๊ธฐ์ ๊ด๋ จ์๋ ์๋ช
์ฃผ๊ธฐ ํ
.
์ปดํฌ๋ํธ ๋ง์ดํธ, ์์กด ๋ชฉ๋ก ์กฐ๊ฑด, ์ธ๋ง์ดํธ ์ ์ฒ๋ฆฌ ํ ์์
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{ /* React Hook, React๊ฐ ์ ๊ณต */}
import React, {useEffect} from 'react'
{ /* ์์กด์ฑ ๋ชฉ๋ก์ ์๋ ์กฐ๊ฑด ์ค ์ด๋ ํ๋๋ผ๋ ์ถฉ์กฑ๋๋ฉด ๊ทธ๋๋ง๋ค ์ฝ๋ฐฑ ํจ์ ์คํ */}
useEffect(์ฝ๋ฐฑ, ์์กด์ฑ๋ชฉ๋ก)
useLayoutEffect(์ฝ๋ฐฑ, ์์กด์ฑ๋ชฉ๋ก)
์ฝ๋ฐฑ = () => { }
{ /* ์ฝ๋ฐฑ ํจ์๋ ํจ์ ๋ฐํ ๊ฐ๋ฅ, ์ปดํฌ๋ํธ๋ฅผ ์ธ๋ง์ดํธ ํ ๋ ๋จ ํ ๋ฒ ์คํ ๋จ*/}
์ฝ๋ฐฑ = () => { return ๋ฐํํจ์ }
{ /* ์ปดํฌ๋ํธ ์์ฑํ ๋ ํ ๋ฒ๋ง ์คํํ๋ ค๋ฉด ์์กด์ฑ ๋ชฉ๋ก์ ๋น ๋ฐฐ์ด [] */}
useEffect(() => {}, [])
{ /* ํจ์ ๋ฐํ ๊ฐ๋ฅ */}
useEffect(() => { /* some */ return () => {} }, [])
{ /* setInterval ํ ๋ฒ๋ง ์คํ๋์ด์ผ ํ๋๋ฐ, ์ฌ๋ ๋๋ง๋ง๋ค ์คํ๋๊ธฐ์ */}
{ /* useEffect(() => {}, [])๋ฅผ ํตํด ์ฒ์ ๋ง๋ค์ด์ง ๋๋ง ํ ๋ฒ ์คํ๋๋๋ก */}
์ฝ๋ฐฑ์์ ํจ์๋ฅผ ๋ฐํํ ์ ์๋๋ฐ, ์ด ๋ฐํ ํจ์๋ ์ปดํฌ๋ํธ๋ฅผ ์ธ๋ง์ดํธํ ๋ ๋จ ํ ๋ฒ๋ง ์คํํ๋ค.
์์กด์ฑ์ด ๋ณํํ๋ฉด ์ฝ๋ฐฑ์ด ๋ฐํํ ์ข
๋ฃ ํจ์๋ฅผ ํธ์ถํ์ฌ ์ฝ๋ฐฑ์ ํ๊ดดํ๊ณ , ์์ ์ ๋งค๊ฐ๋ณ์๋ก ์
๋ ฅํ ์ฝ๋ฐฑ์ ๋ค์ ํธ์ถ
@ TODO : ์ดํด ๋ชปํจ
๋ฆฌ์กํธ ๋ค์ดํฐ๋ธ ์ฝ์ด ์ปดํฌ๋ํธ๋ onLayout ์ด๋ฒคํธ ์์ฑ์ ์ ๊ณตํ๋ค, โreact-nativeโ ํจํค์ง๋ LayoutChangeEvent ํ์ ์ ์ ๊ณตํ๋ค.
LayoutChangeEvent๋ onLayout ์ด๋ฒคํธ ์์ฑ์ ์ค์ ํ๋ ์ด๋ฒคํธ ์ฒ๋ฆฌ๊ธฐ์ ์ ๋ ฅ ๋งค๊ฐ๋ณ์ ํ์ ์ด๋ค.
LayoutChangeEvent์ nativeEvent ์์ฑ์ ํตํด ํน์ ํ์ layout์ ์ป์ ์ ์๋ค.
1
2
3
4
5
6
7
8
9
const onLayout = (e: LayoutChangeEvent) => { /* e.nativeEvent ~ */}
export interface LayoutChangeEvent
{
nativeEvent:
{
layout: LayoutRectangle;
};
}
onLayout ์ด๋ฒคํธ๋ฅผ ํธ์ถํ๋ค๋ ๊ฒ์ ์ปดํฌ๋ํธ์ ๋ ๋๋ง์ด ๋๋ฌ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
๋ง์ดํธ ๊ณผ์
์ปดํฌ๋ํธ ๋ ๋๋ง ์์ โ useLayoutEffect โ ํ๋ฉด์ ๋ํ๋จ โ useEffect โ onLayout
์ธ๋ง์ดํธ ๊ณผ์
์ปดํฌ๋ํธ ์ธ๋ง์ดํธ ์์ โ useEffect ๋ฐํ ํจ์ ํธ์ถ โ useLayoutEffect ๋ฐํ ํจ์ ํธ์ถ โ ์ปดํฌ๋ํธ ํ๊ดด
useLayoutEffect ํ ์ ๋๊ธฐ Synchronous๋ก ์คํํ๊ณ , useEffect ํ ์ ๋น๋๊ธฐ Asynchronous๋ก ์คํํ๋ค.
useLayoutEffect ํ ์ ์ฝ๋ฐฑ ํจ์๊ฐ ๋๋ ๋๊น์ง ํ๋ ์์ํฌ๊ฐ ๊ธฐ๋ค๋ฆฌ๊ณ , useEffect ํ ์ ์ฝ๋ฐฑ ํจ์๋ฅผ ๊ธฐ๋ค๋ฆฌ์ง ์๋๋ค.
๊ฐ๋ฅํ๋ฉด useEffect ํ ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค. (๋ฆฌ์กํธ ๊ณต์ ๋ฌธ์ ๊ถ์ฅ ์ฌํญ)
๐ซ ์ปค์คํ ํ - Custom Hook
Something like Design Pattern
์ฌ๋ฌ ๋ฆฌ์กํธ ํ ๊ณผ ์ปค์คํ ํ ์ ์กฐํฉํ์ฌ ์ฌ์ฌ์ฉํ ์ ์๋ ์๋ก์ด ํ ํจ์๋ฅผ ๋ง๋๋ ๊ธฐ๋ฅ์ด๋ค.
์ปดํฌ๋ํธ์ ํ ํจ์ ์ฝ๋ ํจํด์ด ๋น์ทํ๊ธฐ์, ์ด๋ฐ ํ ํธ์ถ์ ์กฐํฉํ์ฌ ๊ฐ๊ฒฐํ๊ฒ ํํํ ์ ์๋ค. (์ถ์ํ, ๊ธด ์ฝ๋ ํจ์๋ก ๋ง๋ค์ด๋ฒ๋ฆฌ๋ ๊ฒ์ฒ๋ผ)
๋ฆฌ์กํธ ํ ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก, ํจ์ ์ด๋ฆ์ ํญ์ โuse~โ๋ก ์์ํด์ผ ํ๋ค.
useHooks, useHooks-ts ๊ฐ์ ์ฌ์ดํธ์์ ๋ค๋ฅธ ์ฌ๋๋ค์ด ๋ง๋ ํ , ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ ์ ์๋ค.