1. React Hook
1-1. React Hook이란? :
Hook은 16.8버전부터 새로 추가된 기능입니다.
함수형 컴포넌트에서도 상태 값을 관리하거나 그 밖의 여러 React 기능을 사용할 수 있게 하기 위해 태어났어요.
훅은 자바스크립트 함수. 아래처럼 생김.
useEffect(() => {
// something...
}, [])
Hook의 종류는
useState, useEffect, useContext, → 기본 hook
useReducer, useCallback, useMemo, useRef, useImperativeHandle, useLayoutEffect, useDebugValue → 추가 hook
가 있음.
1-2. Hook을 사용할 때 규칙
1. 오직 함수형 컴포넌트에서만 쓸 수 있음.
조금 더 정확히는 React Function 내에서만 쓸 수 있음!
→ 리액트 함수는 리액트의 규칙을 따르는 함수정도로 생각. 함수형 컴포넌트와 커스텀 훅이 대표적.
(커스텀 훅은 커스텀 훅 만들기 때 조금 더 자세히 다뤄볼거임. 😊 )
2. 컴포넌트의 최상위에서만 호출할 수 있음.
반복문, 중첩문 내에서는 호출할 수 없음.
→ 반복문, 중첩문 등에서 훅을 호출하게 될 경우,
컴포넌트가 렌더링할 때 훅의 실행 순서를 늘 동일하게 보장해줄 수 없기 때문.
1-3. 자주 써먹는 Hook
1. useState() :
useState()는 상태관리를 위한 훅.
상태 관리 :
이미 앞서 배운 내용이지만, 중요한 개념이니까 다시 한 번 짚어볼게요.
컴포넌트가 리턴하는 리액트 엘리먼트는 불변 객체라고 말씀드린 적이 있지요?
이 불변 객체의 자식 노드 등 무언가를 바꿔주고 싶다면 어떤 값이 변했으니 어디를 업데이트하라고 해주어야 합니다.
state는 여기서 어떤 값을 담당해요.
그리고 값이 변했다는 걸 명확히 알려주려면 임의로 값을 할당해서는 안됩니다.
정해진 규칙대로 값을 업데이트 해주어야 해요.
useState()는 값을 넣어두고 참조하기 위한 변수(state 변수), 값을 바꿔주기 위한 함수를 반환합니다.
const [someValue, setValue] = useState("hi!");
구조 분해 할당 :
구조 분해 할당은 자바스크립트 표현식 중 하나입니다.
배열이나 객체의 속성을 해체해서 각각의 값을 개별 변수에 할당하게 해주는 거예요.
배열이나 딕셔너리의 []나 {}를 제거하고 안에 담긴 걸 새 변수에 담는다고 생각하면 편합니다.
위의 예시 코드에서는,
const [someValue, setValue] = useState(”hi!”); 에서 useState는 [a, b]를 리턴해주고 있고,
a와 b를 한 번에 가져오기 위해 [someValue, setValue]로 받아오는 거예요.
2. useEffect() :
useEffect()는 컴포넌트의 사이드 이펙트 관리를 위한 훅.
컴포넌트가 화면에 처음 그려진 후, 화면에서 수정된 후, 화면에서 사라질 때 어떤 작업을 주로 할까요?
네! API에서 어떤 데이터를 가져오거나, 이벤트 리스너를 구독하거나 혹은 스피너를 띄워주거나
(이런 건 DOM 수정이죠!) 등등의 작업을 할거예요.
이런 모든 것을 사이드 이펙트라고 합니다.
useEffect()는 그런 사이드 이펙트를 관리하기 위한 훅이에요.
useEffect(() => {
if(is_loaded){
window.alert("hi! im ready! ٩(๑•̀o•́๑)و");
}
return () => {
window.alert("bye!");
}
}, [is_loaded]);
위에서 사용한 useEffect의 인자는 2개.
- 첫번째 인자는 컴포넌트가 화면에 그려질 때(처음 그려질 때와 수정되어 다시 그려질 때 모두!) 실행할 함수.
- 두번째 인자는 디펜던시 어레이라고 부름. 의존성 배열.
배열에 넣은 어떤 값이 변했을 때 useEffect에 넘긴 첫번째 인자를 다시 실행.
- return () ⇒ {} 부분을 clean up이라고 부름.
컴포넌트가 화면에서 사라질 때 마지막으로 정리(청소)한다는 것.
이벤트 리스너 등을 구독해제할 때 주로 여기서 함.
3. useCallback() :
useCallBack()는 함수를 메모이제이션 하기 위한 훅.
useEffect()와 사용법이 상당히 유사함.
메모이제이션이란 쉽게 말해 메모리 어딘가에 저장해두고 두고두고 써먹겠다는 거예요.
함수형 컴포넌트가 리렌더링되면 컴포넌트 안에 선언해둔 함수나 인라인으로 작성한 함수를 다시 한 번 생성하게 돼요. 어떤 컴포넌트가 총 10번 렌더링된다면 그 안에 작성해둔 함수들도 10번 만들어지는거고
이건 메모리 관리에 그리 효율적이지 않습니다. 😖
useCallBack()은 함수를 메모이제이션해서 여러번 만들지 않게 해줘요.
주로 자식 컴포넌트에게 전달해주는 콜백 함수를 메모이제이션할 때 씁니다.
const myNewFunction = useCallback(() => {
console.log("hey!", need_update);
}, [need_update]);
useEffect와 마찬가지로 인자는 2개.
- 첫번째 인자는 실행할 콜백 함수.
- 두번째 인자는 디펜던시 어레이라고 불리는 의존성 배열.
배열에 넣은 어떤 값이 변했을 때 콜백함수를 새로 생성하고 다시 메모이제이션.
useCallback()은 함수를 최적화하기 위한 방법 중 하나예요.
보통 React.memo와 함께 사용해서 불필요한 렌더링을 방지하기 위해 씁니다.
오늘 맛보기로 배워보았지만 useCallback()을 사용한다고 해서 무조건 렌더링 횟수가 줄어들지 않습니다.
오히려 무분별하게 메모이제이션하는 건 좋지 않아요.
주로 자식 컴포넌트에게 props로 넘기는 콜백함수를 감싸는 데에 쓰입니다.
4. useRef() :
useRef()는 ref객체를 다루기 위한 훅.
useRef()는 쉽게 설명하면 도플갱어 박스예요.
어떤 값을 넣어주면 그 값으로 초기화된 변경 가능한 ref 객체를 반환해주거든요!
그리고 이 값은 원본이 아니라 똑같이 생긴 다른 값이라 변경도 됩니다.
변경한다고 해도 리렌더링은 일어나지 않습니다.
const Input = () => {
const input_ref = React.useRef(null);
const clicker = (input_ref) => {
console.log(input_ref);
}
return (
<>
<input ref={input_ref}/>
<button onClick={clicker}>button</button>
</>
);
}
- .current
- useRef는 .current 안에 값을 담아줌.
- 이 값을 변경해도 리렌더링은 일어나지 않음.
- useRef()는 주로 화면에 이미 노출된 것들을 관리할 때 사용함.
- 인풋을 다루거나(포커스를 다루거나, 변경된 텍스트를 받아와야 하거나 등)
- 버튼 클릭 후 등, 특정 상황에서 어떤 인터렉션을 보여주고 싶을 때
- DOM만을 위한 것은 아님.
- 엘리먼트 외에도 특정 값을 다루기 위해 사용할 수 있음.
1-4. Custom Hook
- [완성] 버튼 컴포넌트가 여러개가 된다면? :
퀴즈에서 만든 텍스트 입력기에서 텍스트 영역에 텍스트를 넣어주는 또 다른 컴포넌트가 생긴다고 생각해보자.
(Quiz는 다음 react 게시물에 있음.)
다른 컴포넌트가 생긴다면 ref를 가져오고 state에 값을 넣어주는 코드를 다시 작성해야겠죠.
이렇게 반복적인 로직이 여러개가 될 때는 해당하는 로직을 묶어서 하나의 함수로 빼놓으면 편합니다.
여러번 같은 코드를 작성할 필요 없이 함수 하나만 불러다 쓰면 되니까요!
- custom hook이란? : 반복되는 로직을 재활용하는 방법 중 하나.
자바스크립트 함수에서는 반복되는 코드를 효율적으로 관리하기 위해 또 다른 함수로 묶어서 사용하곤 합니다.
커스텀 훅은 컴포넌트 내에서 훅을 사용하는 로직을 따로 분리하기 위한 거예요. 😊
(컴포넌트도 훅도 함수니까요!)
- useCompletes 훅 만들기
custom hook도 결국 함수입니다. 리액트 함수지요.
일반 자바스크립트 함수처럼 막 만들 수는 없고, 약간의 규칙이 있어요.
1. 함수 명이 use로 시작해야 한다.
2. 최상위에서만 호출할 수 있다.
3. 리액트 함수 내에서만 호출할 수 있다.
4. 꼭 return 값을 주자.
//useCompletes.js
import React from "react";
export const useCompletes = (initial) => {
const [text, setText] = React.useState(initial);
const setBoxText = (_ref) => {
const value = _ref.current?.value;
if (value && value !== "") {
setText(value);
_ref.current.value = "";
}
};
return [text, setBoxText];
};
커스텀 훅은 아래처럼 사용할 수 있음.
//App.js
import "./App.css";
import React from "react";
import { TextArea, Button, Input } from "./components";
import { useCompletes } from "./useCompletes";
function App() {
const input_ref = React.useRef(null);
const [text, setText] = useCompletes("");
return (
<div className="App" style={{ display: "flex", gap: 10 }}>
<div> <TextArea text={text} /> </div>
<div>
<Input input_ref={input_ref} />
<Button setText={setText} input_ref={input_ref} />
</div>
</div> );
}
export default App;
// components.js
import React from "react";
export const TextArea = ({text}) => {
return (
<div style={{ width: "50vw", border: "1px solid #888", minHeight: "20vh" }}>
<pre>{text}</pre>
</div>
);
};
export const Button = ({ input_ref, setText }) => {
return (
<button onClick={() => { setText(input_ref); }} > 완성 </button>
);
};
export const Input = ({ input_ref }) => {
return <input ref={input_ref} />;
};
'(심층)리액트' 카테고리의 다른 글
다시 시작하는 리액트 - 리액트 심화 2-2 (1) | 2023.05.03 |
---|---|
다시 시작하는 리액트 - 리액트 심화 2 Quiz (0) | 2023.05.02 |
다시 시작하는 리액트 - 리액트 심화 1 과제 (0) | 2023.04.30 |
다시 시작하는 리액트 - 리액트 심화 1-3 (0) | 2023.04.30 |
다시 시작하는 리액트 - 리액트 심화 1-2 (0) | 2023.04.27 |
github : https://github.com/dnjfht
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!