천진난만 코딩 스토리
2023.03.03) 항해 26일차 (2-React Hooks) 본문
리액트 훅.......
이게 매우 중요하다는 것도 알고, 어려운 내용이고 공부할 양이 많다고 다들 말해주셨다.
근데 주어진 자료를 보고 자료수집을 더 해보아도,
어떻게 사용하는 것인지, 어떤 상황에서 사용하는지 감은 잡히지만,
막상 코드로 작성해보려니 코드적인 상황이 떠오르지 않아서 좀 멘탈이 터졌다...
많이 사용해보고 적응해야 하는 건 알지만, 아직은 많이 사용해볼 만한 상황을 못 찾았다........
1) Reat Hooks
① useState
setState를 사용하는 방식에는 우리가 알고 있는 방식이 아닌 또 다른 방식인 함수형 업데이트 방식이 있다.
일반 업데이트 방식은 버튼을 클릭했을 때 setNumber가 각각 실행되는 것이 아니라, 배치(batch)로 처리한다.
-아래코드를 참고하여 설명하자면-
우리가 onClick을 했을 때 setNumber 라는 명령을 세번 내리지만, 리액트는 그 명령을 하나로 모아 한번만 실행한다.
그래서 setNumber을 3번 명령하던, 100번 명령하던 1번만 실행된다.
반면에 함수형 업데이트 방식은 3번을 동시에 명령을 내리면, 그 명령을 모아 순차적으로 각각 1번씩 실행한다.
0에 1더하고, 그 다음 1에 1을 더하고, 2에 1을 더해서 3이 되는 것이다.
useState가 이렇게 동작하는 이유는,
리액트는 불필요한 리-렌더링을 방지(렌더링 최적화)하기 위해
즉, 리액트의 성능을 위해 한꺼번에 state를 업데이트 하기에 나타나는 결과이다.
const App = () => {
const [number, setNumber] = useState(0);
return (
<div>
// 일반적인 방법 {/* 버튼을 누르면 1씩 플러스된다. */}
<div>{number}</div>
<button
onClick={() => {
setNumber(number + 1); // 첫번째 줄
setNumber(number + 1); // 두번쨰 줄
setNumber(number + 1); // 세번째 줄
}}
>
버튼
</button>
//함수형 업데이트 방법 {/* 버튼을 누르면 3씩 플러스 된다. */}
<div>{number}</div>
<button
onClick={() => {
setNumber((previousState) => previousState + 1);
setNumber((previousState) => previousState + 1);
setNumber((previousState) => previousState + 1);
}}
>
버튼
</button>
</div>
);
}
export default App;
```
② useEffect
useEffect는 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook이다.
어떤 컴포넌트가 화면에 보여졌을 때(혹은 사라졌을 때) 내가 무언가를 실행하고 싶다면 useEffect를 사용한다.
//useState와 마찬가지로 React에서 제공하는 훅 (기능) 이므로,
import React, { useEffect } from "react";
//로 import 해서 사용해야한다.
useEffect는 useEffect가 속한 컴포넌트가 화면에 렌더링 될 때 실행된다.
그렇기에 원치 않는 상황에서도 렌더링에 의해 실행되는 경우도 있다.
이 경우에는 의존성 배열을 사용하여 해결할 수 있다.
❶ 의존성 배열(dependency array)
"이 배열에 값을 넣으면 그 값이 바뀔 때만 useEffect를 실행할게" 라는 것 이다.
// useEffect의 두번째 인자가 의존성 배열이 들어가는 곳 입니다.
useEffect(()=>{
// 실행하고 싶은 함수
}, [의존성배열])
어떤 함수를 컴포넌트가 렌더링 될 때 단 한번만 실행하고 싶으면 의존성 배열을 [ ] 빈 상태로 넣으면 된다.
➂ useRef
DOM 요소에 접근할 수 있도록 하는 React Hook 이다.
리액트에서도 DOM을 선택해야 할 상황이 생길 때, useRef hook을 사용한다.
ex) 화면이 렌더링 되자마자 특정 input 태그가 focusing이 돼야 하는 경우 등
const ref = useRef("초기값");
console.log("ref 1", ref);
ref.current = "바꾼 값";
console.log("ref 1", ref);
다만, 이렇게 설정된 ref 값은 컴포넌트가 계속해서 렌더링 되어도 unmount 전까지 값을 유지한다는 것을 주의해야한다.
이러한 특징 때문에 useRef는 다음 2가지 용도로 사용된다.
- 저장공간
- state와 비슷한 역할을 한다. (다만 state는 변화가 일어나면 다시 렌더링이 일어나서 내부 변수들은 초기화)
- ref에 저장한 값은 렌더링을 일으키지 않는다. (ref의 값 변화가 일어나도 내부 변수들이 초기화 X)
- state는 리렌더링이 꼭 필요한 값을 다룰 때 쓰면 된다.
- ref는 리렌더링을 발생시키지 않는 값을 저장할 때 사용한다.
- DOM
- 렌더링 되자마자 특정 input이 focusing 돼야 한다면 useRef를 사용한다.
④ useContext
props를 하여 GrandFather 컴포넌트 > Father 컴포넌트 > Child 컴포넌트로 name을 전달해준다하면,
Father 컴포넌트는 중간다리 역할을 하게 된다. 근데 만약, Father 컴포넌트가 100개가 넘는다면?
굉장히 비효율적이다. 이 비효율적인 방법을 대신하도록 useContext를 사용할 수 있다.
//context > FamilyContext.js
import { createContext } from "react";
// 여기서 null은 createContext의 기본값이다.
export const FamilyContext = createContext(null);
context 를 생성하고,
import React from "react";
import Father from "./Father";
import { FamilyContext } from "../context/FamilyContext";
function GrandFather() {
const name="olaf";
return (
<FamilyContext.Provider value={{ name }}> //Provider란 제공자
<Father /> //context에서 전해주기에 props가 필요없다.
</FamilyContext.Provider>
);
}
export default GrandFather;
context에서 전해줄 것이기 때문에 더 이상 props가 필요없다.
그렇기에 FamilyContext.Provider로 전해주고,
props를 받던 Father 컴포넌트에서도 Child에게 props를 줄 필요가 없다.
import React, { useContext } from "react";
import { FamilyContext } from "../context/FamilyContext"; //연결
function Child({ name }) {
const data = useContext(FamilyContext); //적용
return (
<div>
이름은 <span style={stressedWord}>{data.name}</span>랍니다.
//props로 내려준 값이 아니라 context를 이용해서 값을 받아옴.
</div>
);
}
export default Child;
- 주의할 점
- useContext를 사용할 때, Provider에서 제공한 value가 달라진다면,
- useContext를 사용하고 있는 모든 컴포넌트가 리렌더링 된다.
- value 부분을 항상 신경써야 하고, 그 대안으로 메모이제이션이 있다.
'TIL(Today I Learned)' 카테고리의 다른 글
2023.03.04) 항해 27일차 (1-Redux) (0) | 2023.03.04 |
---|---|
2023.03.03) 항해 26일차 (3-React Hooks 최적화) (0) | 2023.03.03 |
2023.03.03) 항해 26일차 (1-CSS-in-JS,전역스타일링) (0) | 2023.03.03 |
2023.03.02) 항해 25일차 (0) | 2023.03.02 |
2023.02.28) 항해 23일차 (0) | 2023.03.01 |