👉 React Hooks란?
React 에서 기존에 사용하던 Class를 이용한 코드를 작성할 필요 없이,
state와, 여러 React 기능을 사용할 수 있도록 만든 라이브러리
React Hook 개발 과정
1. 클래스 컴포넌트 사용
2. 함수 컴포넌트와, 리액트 훅 사용
( 리액트 훅은, 함수 컴포넌트에서만 사용가능하다 )
함수 컴포넌트가 어떤 값을 유지할 수 있도록, '캐시'를 만들었다.
이 캐시를 이용하고자 만든 여러개의 API를 '리액트 훅' 함수라고 부른다.
React Hook의 필요성
함수 컴포넌트도 클래스 컴포넌트처럼 사용할 수 있다.
함수 컴포넌트는 클래스 컴포넌트와 다르게, 모듈로 활용하기가 쉬우므로 ( why? )
서로의 장점을 전부다 가지고 있다.
👉 React Hooks 사용규칙
같은 Hook을 여러번 호출할 수 있다.
export default function App(){
const [value1, setValue1] = useState()
const [value2, setValue2] = useState()
return {
<div>
<div>{value1}</div>
<div>{value2}</div>
</div>
}
}
함수 컴포넌트 몸통이아닌, 몸통 안 복합 실행문의 {}에서는 사용할 수 없다.
javascript의 block scope는, block 외에서 사용할 수 없으므로 ( 지역변수이기 때문에 )
export default function App(){
return {
<div>
// 불가능
<div>{const [value, setvalue] = useState()}</div>
</div>
}
}
비동기 함수(async 키워드가 붙은 함수)는 콜백함수로 사용할 수 없다.
export default function App(){
// useEffect Hook 내부에, 비동기 함수가 들어가므로 에러 발생
useEffect(async () => {
await Promise.resolve(1)
}, [])
return {
<div>
<div>Test</div>
</div>
}
}
👉 React에서 기본적으로 지원하는 Hooks
1. useState
컴포넌트의 state(상태)를 관리 할 수 있다.
상태에 따라, 다른 화면 출력
2. useEffect
렌더링 이후에 실행할 코드를 만들수 있다.
어떤 변수가 변경될때마다(의존성), 특정기능이 작동하도록 할 수 있다.
3. useContext
부모컴포넌트와 자식컴포넌트 간의 변수와 함수를 전역적으로 정의할 수 있다.
4. useReducer
state(상태) 업데이트 로직을, reducer 함수에 따로 분리 할 수 있다.
5. useRef
컴포넌트나 HTML 요소를 래퍼런스로 관리할 수 있다.
6. forwardRef
useRef로 만든 래퍼런스를 상위 컴포넌트로 전달할 수 있다.
7. useImperativeHandle
useRef로 만든 래퍼런스의 상태에 따라, 실행할 함수를 정의 할 수 있다.
8. useMemo, useCallback
의존성 배열에 적힌 값이 변할 때만 값,함수를 다시 정의할 수 있다. ( 재랜더링시 정의 안함 )
8. useLayoutEffect
모든 DOM 변경 후 브라우저가 화면을 그리기(render)전에 실행되는 기능을 정할 수 있다.
9. useDebugValue
사용자 정의 Hook의 디버깅을 도와준다.
👉 useState 사용법
state란?
React에서 사용자의 반응에 따라, 화면을 바꿔주기(렌더링) 위해 사용되는 트리거역할을 하는 변수
React가 state를 감시하고, 바뀐 정보에 따른 화면을 표시해준다.
( state와 setState함수의 반환값을 비교 )
state 만들기 ( useState 사용 )
// React에 기본적으로 내장되어 있는 useState 훅을 사용하면, state를 만들 수 있다.
import { useState } from "react";
// const [state, state변경함수] = useState(기본 state값);
const [isLoggedIn, setIsLoggedIn] = useState(false);
state 변경하기 (사용자 반응에 따른 다른 화면 보여주기)
// 전에 만든 "isLoggedIn" state의 값을 true로 변경한다.
setIsLoggedIn(true);
// ** useState함수를 사용해 만든 "state 변경 함수"를 사용하여야 한다.
state의 특징
state는 어디에서든지 사용가능하다.
하지만 컴포넌트는 시간이 지나고, 앱이 커질수록 점점 많아지므로
점점 관리가 어려워지는 단점이 있다?
useEffect와 useLayoutEffect의 차이점
useEffect | useLayoutEffect |
비동기 방식 | 동기 방식 ( 끝날때까지 React가 기다려줌 ) |
👉 useEffect 사용법
// React에 기본적으로 내장되어 있는 useState와, useEffect 불러오기
import { setState, useEffect } from "react";
...
function App() {
const [data, changeData] = setState(false)
// useEffect(실행할 함수, 트리거가 될 변수)
useEffect(() => {
if (data.me === null) {
console.log("Data changed!")
}
return () => console.log("컴포넌트 파괴, 언마운트 됨")
}, [data]);
// data변수가 바뀔때마다, react가 이를 감지해, 콘솔창에 "Data changed!" 출력
return (
<div>
<button value="적용" onClick={changeData(!data)} />
</div>
)
}
export default App;
👉 useLayoutEffect 사용법
// React에 기본적으로 내장되어 있는 useState와, useEffect 불러오기
import { setState, useLayoutEffect } from "react";
...
function App() {
const [data, changeData] = setState(false)
// useLayoutEffect(실행할 함수, 트리거가 될 변수)
useLayoutEffect(() => {
if (data.me === null) {
console.log("Data changed!")
}
return () => console.log("Layout 사라짐")
}, [data]);
// data변수가 바뀔때마다, react가 이를 감지해, 콘솔창에 "Data changed!" 출력
return (
<div>
<button value="적용" onClick={changeData(!data)} />
</div>
)
}
export default App;
👉 useContext 사용법
새로운 context 만들기
// newContext.js
import { createContext } from "react" // createContext 함수 불러오기
// context안에 homeText란 변수를 만들고, 공백("") 문자를 저장한다.
const newContext = createContext({
homeText: "",
})
context를 사용할 부분 선택하기, 새로운 정보 저장하기
// App.js
import React from "react";
import { View } from "react-native";
import Home from "./Home"; // 자식 컴포넌트 불러오기
import { newContext } from "./newContext"; // context 불러오기
export default function App() {
// context에 저장할 정보를 입력한다.
const homeText = "is Worked!"
// NewContext.Provider로 우리가 만든 context를 사용할 부분을 감싸준다.
return (
<newContext.Provider value={{ homeText }}>
<View>
<Home />
</View>
</newContext.Provider>
);
}
context 사용하기
// Home.js
import React from "react";
import { Text, View } from "react-native";
import { useContext } from "react";
import { newContext } from "../newContext";
export default function Home() {
// useContext hook 사용해서, newContext에 저장된 정보 가져오기
const { homeText } = useContext(newContext);
// 불러온 정보 사용하기!!
return (
<View>
<Text>{homeText}<Text>
</View>
);
}
context 사용시 좋은점
React에서 context 없이 변수나 함수를 다른 컴포넌트로 전달하려면
부모자식간에만 전달이 가능하므로,
컴포넌트가 많아질수록 불필요한 컴포넌트를 많이 거쳐야하는 문제가 발생한다! ( A -> B -> C -> D )
context를 이용하면, 중간과정을 재치고 직통으로 전달할 수 있다! ( A -> D )
context 사용시 유의점
전달하고자하는 컴포넌트에 context를 만들면, 불필요한 호출이 추가될 수 있으므로,
context 전용 파일을 만들어야 한다.
예시 조건 )
컴포넌트 : A, B, C, D ( A가 최상위 컴포넌트 )
전달 : A -> D
A 컴포넌트에 context 생성
D 컴포넌트에서 context 불러옴
실행 과정 )
1. A가 렌더링되며, B, C, D를 차례로 불러옴
2. D에서 context를 가져오기위해 A를 다시불러옴
3. A를 다시 불러오면서, 불필요한 중복이 발생함
👉 useMemo 사용법
Memoization : 과거에 계산한 값을 반복해서 사용할때, 그 값을 캐시에 저장하는 것
- 재귀함수에 사용하면, 불필요한 반복 수행을 대폭 줄일 수 있다.
- 의존성을 가지므로, 첫렌더링시에만 저장할 변수를 설정할 수 있다.
export default function App(){
const data = useMemo(()=> "data",[]);
// 데이터 변수는 의존성 배열 []에따라 선언된다. ( []사용시, 첫 렌더링 시에 1번만 선언 )
return <></>
}
👉 useCallback 사용법
useMemo의 함수버전. 반복적으로 사용되는 함수를 캐시에 저장할 수 있다.
export default function App(){
const avatarPressed = useCallback(() => Alert.alert('avatar pressed.'), []);
return <></>
}
👉 useRef 사용법
HTML요소(태그)나 컴포넌트의 메모리주소를 가져와, 객체(레퍼런스) 형식으로 관리할 수 있다.
- current 속성을 가지고 있는 객체를 반환한다.
- current 값이 바뀌어도, 재렌더링 되지 않는다.
- 재렌더링시에도, current 값은 없어지지 않는다.
export default App(){
// 괄호()속에 초기값 입력
const viewRef = useRef(null)
// viewRef 객체에 있는 메소드를 사용한다.
function testFunc(){
viewRef.current?.메소드()
}
/// viewRef요소에, 해당 메모리 주소 전달
return <View ref={viewRef}>
<Text>Test</Text>
</View>
}
👉 forwardRef 사용법
부모 컴포넌트와, 자식 컴포넌트가 [함수형 컴포넌트]로 정의 되었을때,
부모 컴포넌트에서, 자식 컴포넌트를 객체 형식으로 관리할 수 있다.
// 자식 컴포넌트
import {forwardRef} from 'react'
// 부모 컴포넌트의 ref를 인자로 받아올 수 있다.
const _TextInput = (
props,
ref
) => {
// 자식 컴포넌트의 ref에 useRef()객체 전달
return (
<View>
<Text>Hello</Text>
<TextInput
ref={ref}
{...props}
/>
</View>
);
};
// forwardRef()으로 감싸주기
export const MyTextInput = forwardRef(_TextInput);
// 부모 컴포넌트
import {useRef} from 'react'
const Parent = () => {
const testRef = useRef(null);
const setFocus = () => testRef.current?.focus();
// 자식 컴포넌트에게 ref 전달
return <ImperativeTextInput ref={testRef} />
};
👉 useImperativehandle 사용법
useRef으로 만든 컴포넌트 객체(레퍼런스)안에, 커스텀 메서드(함수)를 만들 수 있다.
import {useRef, useImperativeHandle} from 'react'
const ImperativeTextInput = (props, ref) => {
const textInputRef = useRef<TextInput | null>(null);
// ref을 전달받아, 메소드를 만들어준다. ( 다른 ref 호출 가능 )
useImperativeHandle(
ref,
() => ({
focus() {
textInputRef.current?.focus();
},
dismiss() {
Keyboard.dismiss();
},
}),
[],
);
return <TextInput ref={textInputRef} {...props} />;
};
export default forwardRef(ImperativeTextInput);
useImperativeHandle
useReducer 사용법 (Redux개념)
여러개의 상태를 통합해 관리한다.
state : 상태
action : 변화내용 객체
reducer : state와 action 인자로 받아, 다음 상태 반환하는 함수
dispatch : action을 반환하는 함수
필요성
useState를 여러번 사용하는 경우 유용하다
상태를 업데이트하는 로직을, 컴포넌트 밖에 작성 가능
dispatch라는 함수로, 상태 통합 관리 -> Context와 함께 사용하면 유용?
------------- 추후 업데이트 ----------------
// 동시에 여러 상태값 업데이트
const onPress = () => {
setMode('hype');
setText('We are Hyped!');
setRed(true);
}
// dispatch에게 인자를 전달받음
function reducer(state, action){
// state에 이전 상태값 들어있음
// action에 {키:값, ...} 형식의 객체(action)가 들어있음
switch (action.type) {
case 'hype':
// 상태값 변환
return {text: action.text, red: true};
case 'carm':
return {...state, red: false};
default
throw new Error('action type이 없습니다.');
}
}
function Sence(){
// 1번째 : reducer 함수, 2번째 : 초기 상태값
const [state, dispatch] = useReducer(reducer, initialState);
// dispatch 함수에 {키:값, ...} 형식의 객체를 전달
const onChange = () => dispatch({type: 'hype', text: 'We are Hyped!'});
const onDecrease = () => dispatch({type: 'carm'});
...
}
cache
React.js는 컴포넌트 내부에서 전역변수를 사용할 수 있도록,
cache 객체 안에, key : value 형식으로 저장하는 방식을 사용한다.
// 전역적인 캐시 생성
const cache: Record<string, any> = {};
export default function createOrUse<T>(key: string, callback: () => T) {
if (!cache[key]) {
cache[key] = callback();
// 키 : 값 저장
}
return cache[key];
// 입력한 키에 해당하는 값 반환
}
의존성
React.js의 캐시는, 상황에 따라 업데이트하도록 만드는 의존성 배열을 만들 수 있다.
( 배열 속의 값이 바뀔때마다, 캐시를 업데이트 한다. )
// 전역적인 캐시 생성
const cache: Record<string, any> = {};
export default function createOrUse<T>(key: string, callback: () => T) {
if (!cache[key]) {
cache[key] = callback();
// 키 : 값 저장
}
return cache[key];
// 입력한 키에 해당하는 값 반환
}
여러가지 React Hooks 라이브러리
1. react-hook-form
https://defineall.tistory.com/900
'개념 창고 > React' 카테고리의 다른 글
[React] Context란? (0) | 2023.03.31 |
---|---|
[React] Composition vs Inheritance (0) | 2023.03.30 |
[React] Form (0) | 2023.03.30 |
[React] List and Keys (0) | 2023.03.30 |
[React] 조건부 렌더링(Conditional Rendering) (0) | 2023.03.30 |
- 👉 React Hooks란?
- React Hook 개발 과정
- React Hook의 필요성
- 👉 React Hooks 사용규칙
- 👉 React에서 기본적으로 지원하는 Hooks
- 👉 useState 사용법
- state란?
- state 만들기 ( useState 사용 )
- state 변경하기 (사용자 반응에 따른 다른 화면 보여주기)
- state의 특징
- useEffect와 useLayoutEffect의 차이점
- 👉 useEffect 사용법
- 👉 useLayoutEffect 사용법
- 👉 useContext 사용법
- 👉 useMemo 사용법
- 👉 useCallback 사용법
- 👉 useRef 사용법
- 👉 forwardRef 사용법
- 👉 useImperativehandle 사용법
- useReducer 사용법 (Redux개념)
- 필요성
- cache
- 의존성
- 여러가지 React Hooks 라이브러리