달마루
기획자에서 개발자로
달마루
전체 방문자
오늘
어제
  • 분류 전체보기 (334)
    • 기획 이야기 (3)
    • 개발자로 전향한 이유 (1)
    • Github Address (1)
    • 개발자, 그 여정 (11)
      • 기초특강 (4)
      • 국비학원 선정 (4)
      • BitCamp_수업내용 (1)
      • 학원 프로젝트 후기 (1)
      • 정보처리기사 (1)
      • 개발 이야기 (0)
    • 개념 창고 (126)
      • JAVA (50)
      • CS (1)
      • Database (27)
      • NetWork (2)
      • 자료 구조 (2)
      • React (8)
      • Spring (3)
      • JPA (1)
      • HTML & CSS (18)
      • JS (3)
    • algorithm (186)
      • 백준 (161)
      • 프로그래머스 (23)
    • 사는 이야기 (0)

블로그 메뉴

  • Github
  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 백준알고리즘
  • Scanner
  • Bronze V
  • 혼공SQL
  • 백준
  • 프로그래머스
  • Bronze IV
  • java
  • 백준문제풀이
  • 혼공MySQL
  • SQL고득점Kit
  • 자바
  • Algorithm
  • MySQL
  • BRONZE
  • 문제풀이
  • programmers
  • 혼자공부하는SQL
  • java algorithm
  • sql 문제풀이
  • SQL
  • 알고리즘풀이
  • math
  • BOJ
  • react
  • 알고리즘
  • HTML
  • BOJ algorithm
  • Bronze III
  • select

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
달마루

기획자에서 개발자로

개념 창고/React

React Hooks

2023. 4. 3. 09:41

👉 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' 카테고리의 다른 글
    • [React] Context란?
    • [React] Composition vs Inheritance
    • [React] Form
    • [React] List and Keys
    달마루
    달마루
    항상 어제보다 좋은 코드를 지향합니다. https://github.com/LimDongHyun99

    티스토리툴바