Hook은 React 16.8에 새로 추가된 기능, Hook은 class를 작성하지 않고도 state와 다른 React의 기능들을 사용할 수 있도록 만든 라이브러리
Class 컴포넌트 vs Function 컴포넌트
hook이 나오기 전 까지는 상태값(state)에 접근, 생명주기 기능(lifecycle features)을 사용하기 위해 class형 컴포넌트 선언을 해줘야 했다.
함수형 컴포넌트는 한번 호출되고 메모리상에서 사라져 상태값 접근과 라이프사이클 구현이 불가능했다. 그러나 class형 컴포넌트를 사용하다보니 아래와 같은 문제점들이 발생했다
Class형 컴포넌트의 문제점
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>
}
}
export default function App(){
// useEffect Hook 내부에, 비동기 함수가 들어가므로 에러 발생
useEffect(async () => {
await Promise.resolve(1)
}, [])
return {
<div>
<div>Test</div>
</div>
}
}
컴포넌트의 state(상태)를 관리 할 수 있다.
상태에 따라, 다른 화면 출력
렌더링 이후에 실행할 코드를 만들수 있다.
어떤 변수가 변경될때마다(의존성), 특정기능이 작동하도록 할 수 있다.
부모컴포넌트와 자식컴포넌트 간의 변수와 함수를 전역적으로 정의할 수 있다.
state(상태) 업데이트 로직을, reducer 함수에 따로 분리 할 수 있다.
컴포넌트나 HTML 요소를 래퍼런스로 관리할 수 있다.
useRef로 만든 래퍼런스를 상위 컴포넌트로 전달할 수 있다.
useRef로 만든 래퍼런스의 상태에 따라, 실행할 함수를 정의 할 수 있다.
의존성 배열에 적힌 값이 변할 때만 값,함수를 다시 정의할 수 있다. ( 재랜더링시 정의 안함 )
모든 DOM 변경 후 브라우저가 화면을 그리기(render)전에 실행되는 기능을 정할 수 있다.
사용자 정의 Hook의 디버깅을 도와준다.
React에서 사용자의 반응에 따라, 화면을 바꿔주기(렌더링) 위해 사용되는 트리거역할을 하는
변수
// React에 기본적으로 내장되어 있는 useState 훅을 사용하면, state를 만들 수 있다.
import { useState } from "react";
// const [state, state변경함수] = useState(기본 state값);
const [isLoggedIn, setIsLoggedIn] = useState(false);
// 전에 만든 "isLoggedIn" state의 값을 true로 변경한다.
setIsLoggedIn(true);
// ** useState함수를 사용해 만든 "state 변경 함수"를 사용하여야 한다.
// 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;
// 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;
useEffect | useLayoutEffect |
---|---|
비동기 방식 | 동기 방식 ( 끝날때까지 React가 기다려줌 ) |
// 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>
);
}
React에서 context 없이 변수나 함수를 다른 컴포넌트로 전달하려면 부모자식간에만 전달이 가능하므로, 컴포넌트가 많아질수록 불필요한 컴포넌트를 많이 거쳐야하는 문제가 발생한다! ( A -> B -> C -> D )
context를 이용하면, 중간과정을 재치고 직통으로 전달할 수 있다! ( A -> D )
단 전달하고자하는 컴포넌트에 context를 만들면, 불필요한 호출이 추가될 수 있으므로, context 전용 파일을 만들어야 한다.
예시 조건 )
컴포넌트 : A, B, C, D ( A가 최상위 컴포넌트 )
전달 : A -> D
A 컴포넌트에 context 생성
D 컴포넌트에서 context 불러옴
실행 과정 )
Memoization : 과거에 계산한 값을 반복해서 사용할때, 그 값을 캐시에 저장하는 것
export default function App() {
const data = useMemo(() => "data", []);
// 데이터 변수는 의존성 배열 []에따라 선언된다. ( []사용시, 첫 렌더링 시에 1번만 선언 )
return <></>;
}
useMemo의 함수버전. 반복적으로 사용되는 함수를 캐시에 저장할 수 있다.
export default function App() {
const avatarPressed = useCallback(() => Alert.alert("avatar pressed."), []);
return <></>;
}
여러개의 상태를 통합해 관리
// 동시에 여러 상태값 업데이트
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'});
...
}
https://velog.io/@niboo/React-Hooks-%EB%9E%80#hook%EC%9D%98-%EA%B7%9C%EC%B9%99
https://defineall.tistory.com/900#toc4