컴포넌트의 상태를 관리할 때 사용하는 Hooks
const [state, dispatch] = useReducer (reducer, initialState);
값 | 설명 |
---|---|
state | 컴포넌트에서 사용할 상태 값 |
dispatch | 액션을 발생시키는 함수 |
reducer | reducer 함수 |
initialState | 초기 상태 값 |
dispatch({ key : value })
// 일반적으로 key 자리에 type 을 많이 사용한다.
function reducer(state, action) {
//새로운 상태를 만드는 로직
return 새로운 상태
}
💡 일반적으로 reducer() 함수는 별도의 파일로 빼놓음 → 재사용하기 위함
useState()
useReducer()
import React from "react";
const countReducer = (state, action) => {
switch (action.type) {
case "INCREMENT":
return state + 1;
case "DECREMENT":
return state - 1;
// react에서는 default 사용하지 않으면 warning 뜸
default:
return state;
}
};
export default countReducer;
import React, { useReducer } from "react";
import countReducer from "./countReducer";
const Counter = () => {
const [state, dispatch] = useReducer(countReducer, 0);
const numUp = () => {
dispatch({ type: "INCREMENT" });
};
const numDown = () => {
dispatch({ type: "DECREMENT" });
};
return (
<div>
<p>
현재 카운터 값은 <b>{state}</b>입니다.
</p>
<button onClick={numUp}>+1</button>
<button onClick={numDown}>-1</button>
</div>
);
};
export default Counter;
[실습] dispatch()에 값 여러개 넣기
const numUp = () => {
dispatch({ type: "INCREMENT" , icon : "🏴" });
};
const numDown = () => {
dispatch({ type: "DECREMENT", icon : "🏴" });
};
import React from "react";
const countReducer = (state, action) => {
switch (action.type) {
case "INCREMENT":
return action.icon;
case "DECREMENT":
return action.icon;
// react에서는 default 사용하지 않으면 warning 뜸
default:
return state;
}
};
export default countReducer;
👉 실행 결과
useMemo()
메모이제이션(Memoization)
useMemo()는 왜 사용하는가?
const memoizedValue = useMemo(
() => {
//연산량이 많은 작업을 수행
return compute(a, b)
}, [a, b]);
첫번째 매개변수
두번째 매개변수
의존성 배열이 빈 배열인 경우
useMemo(() => {
// 연산량이 많은 작업을 수행
return compute(a, b)
},[]);
컴포넌트가 렌더링 될 때마다 콜백함수 호출
useMemo()를 사용하는 의미가 없음
useMemo(() => {
// 연산량이 많은 작업을 수행
return compute(a, b)
});
→ 최초에 한 번 실행 후 결과값 저장, 렌더링이 되더라도 a와 b의 값이 바뀌지 않는 경우 저장된 결과값을 불러와서 사용함
→ 매개변수인 a와 b의 값이 바뀔 때만 compute 함수 실행하고 결과값 저장
[실습] useMemo()를 사용한 계산
import React, { useState } from "react";
function hardCalculate(number) {
console.log("어려운 계산중");
for (let i = 0; i < 1000000; i++) {}
return number + 10000;
}
function easyCalculate(number) {
console.log("쉬운 계산 중");
return number + 1;
}
const UseMemoComponent = () => {
const [hardNumber, setHardNumber] = useState(1);
const [easyNumber, setEasyNumber] = useState(1);
const hardSum = hardCalculate(hardNumber);
const easySum = easyCalculate(easyNumber);
return (
<div>
<h3>어려운 계산기</h3>
<input
type="number"
value={hardNumber}
onChange={(e) => setHardNumber(parseInt(e.target.value))}
/>
<span> + 10000 = {hardSum}</span>
<h3>쉬운 계산기</h3>
<input
type="number"
value={easyNumber}
onChange={(e) => setEasyNumber(parseInt(e.target.value))}
/>
<span> + 10000 = {easySum}</span>
</div>
);
};
export default UseMemoComponent;
const hardSum = useMemo(() => hardCalculate(hardNumber),[hardNumber]);
👉 실행 결과
useMemo 사용 시 주의점
이미 생성해 놓은 함수를 재사용할 수 있게 해주는 Hook
useMemo()와 유사한 Hook
컴포넌트에 useCallBack()을 사용하지 않고 함수를 정의한 경우
첫번째 매개변수
두번째 매개변수
의존성 배열이 빈 배열인 경우
의존성 배열이 없는 경우
[실습] 자바스크립트 함수 동등성
const UseCallBackComponent1 = () => {
const name1 = () => "soo";
const name2 = () => "soo";
console.log("name1 : ", name1);
console.log("name2 : ", name2);
return <div>{name1 === name2 ? "같다" : "다르다" }</div>};
};
export default UseCallBackComponent1;
👉 실행 결과
[실습] useCallback()
import React, { useCallback, useEffect, useState } from "react";
const UseCallBackComponent2 = () => {
const [count, setCount] = useState(0);
const clickHandler = () => {
console.log("count : ", count);
};
return (
<div>
<input
type="number"
value={count}
onChange={(e) => setCount(e.target.value)}
/>
<button onClick={clickHandler}>숫자 출력</button>
</div>
);
};
export default UseCallBackComponent2;
👉 실행 결과
import React, { useCallback, useEffect, useState } from "react";
const UseCallBackComponent2 = () => {
const [count, setCount] = useState(0);
const clickHandler = () => {
console.log("count : ", count);
};
useEffect(() => {
console.log("렌더링 완료");
};
return (
<div>
<input
type="number"
value={count}
onChange={(e) => setCount(e.target.value)}
/>
<button onClick={clickHandler}>숫자 출력</button>
</div>
);
};
export default UseCallBackComponent2;
👉 실행 결과
→ 버튼을 누르지 않아도 계속 렌더링이 됨
import React, { useCallback, useEffect, useState } from "react";
const UseCallBackComponent2 = () => {
const [count, setCount] = useState(0);
const clickHandler = () => {
console.log("count : ", count);
};
useEffect(() => {
console.log("clickHandler()변경");
}, [clickHandler]);
return (
<div>
<input
type="number"
value={count}
onChange={(e) => setCount(e.target.value)}
/>
<button onClick={clickHandler}>숫자 출력</button>
</div>
);
};
export default UseCallBackComponent2;
👉 실행 결과
→ 버튼을 누르지 않아도 계속 렌더링이 됨
→ clickHandler 함수는 주소를 가진 객체이므로 렌더링 될 때마다 주소의 번지가 변경
import React, { useCallback, useEffect, useState } from "react";
const UseCallBackComponent2 = () => {
const [count, setCount] = useState(0);
const clickHandler = useCallback(() => {
console.log("count : ", count);
}, [count]);
useEffect(() => {
console.log("clickHandler()변경");
}, [clickHandler]);
return (
<div>
<input
type="number"
value={count}
onChange={(e) => setCount(e.target.value)}
/>
<button onClick={clickHandler}>숫자 출력</button>
</div>
);
};
export default UseCallBackComponent2;
👉 실행 결과
props
의 변화가 있는지를 체크[실습] useCallback() + React.memo()
function App() {
const [count, setCount] = useState(0);
const updateHandler= () => {
console.log("update");
};
return (
<div>
<input type="number"
onChange={(e) => setCount(e.target.value)} />
<ChildComponent update={updateHandler} />
</div>
);
}
export default App;
const ChildComponent= (props) => {
const { update } = props;
console.log("child component 렌더링");
return <div></div>;
};
export default ChildComponent;
👉 실행 결과
→ updateHandler가 주소를 갖고 있기 때문에 ChildComponent의 변경사항이 없어도 다시 렌더링 된다
[실습] useCallback() + React.memo() - 수정
function App() {
const [count, setCount] = useState(0);
const updateHandler = useCallback (() => {
console.log("update");
}, []);
return (
<div>
<input type="number"
onChange={(e) => setCount(e.target.value)} />
<ChildComponent update={updateHandler} />
</div>
);
}
export default App;
👉 실행 결과
[실습] useCallback() + React.memo() - 수정
import React, { memo } from "react";
const ChildComponent= (props) => {
const { update } = props;
console.log("child component 렌더링");
return <div></div>;
};
export default memo(ChildComponent);
👉 실행 결과
새싹DT 기업연계형 프론트엔드 실무 프로젝트 과정 8주차 블로그 포스팅