세상이 참 좋아졌다. cursor로 바이브코딩이라는 걸 하고 있다. 문법을 하나도 몰라도 된다. 그래도 난 전공자니껜.. 이것저것 물어보면서 새로운 걸 배우면 잡다한 것으로 업로드할 예정이다.
const showLogs = useCallback(
(logs) => {
if (!logs) return;
logs.forEach((l) => addToast(l));
},
[addToast]
);
LLM의 동작 과정을 로그에 기록했다가 사용자 화면에 toast해주는 핵심함수이다.
`useCallback`이 뭔지, `=>` 얘가 뭔지, `[addToast]`가 뭔지 몰라서 찾아봤다.
역시 AI에게 물어봤다. 볼 때는 끄덕이지만, 다시 보면 모르기에 글로라도 남겨둔다.
useCallback
showLogs라는 함수를 메모리 어딘가에 박아둔다.
JS의 일반 함수는 컴포넌트가 다시 그려질(리렌더링)될 때마다 새로 만들어진다.
그런데 useCallback을 사용하면 메모리에 함수를 저장해 두고 재사용 가능하게 해 준다.
=> (Arrow function)
코드를 보면, (logs) => {...}형식의 구조로 되어 있다.
여기서 logs는 매개변수, =>은 매개변수로 실행할 내용이다.
def showlogs(logs):
...
#do something
...
return something
파이썬은 이런 식으로 함수의 정의부터 동작까지 캐주얼룩을 입고 있는 듯한 느낌으로 구획되어있는데,
리액트나 js는 좀 유연한 느낌이다.
(매개변수는 얘니까) => {그걸로 여기 있는 것들 실행해} 형식이다.
[addToast]: 의존성 배열(dependency Array)
리액트에게 이 값이 바뀔 때만 함수를 새로 만들고, 아니면 이전 것을 그대로 쓰라고 명령하는 업데이트 배열 느낌이다.
이걸 안 해주면, 위 코드에서 logs의 하나하나(l)마다 반복하며 `addToast(l)`을 실행해야 하는데, addToast의 기능이 변경되어도 이전의 내용을 기반으로 함수가 실행되기 때문이다. 그래서 항상 감시(?)를 해주어야 한다
요약하면, `useCallback(실행할 함수, 감시할 함수)`의 구조이다.
케이스별로 살펴보자.
1. 의존성 배열이 비어있는 경우 [ ]
처음 상태 그대로를 박제
addToast함수 내용이 바뀌어도 처음에 저장된 그 addToast함수가 실행된다. (알림이 낡은 방식으로 뜬다던지 등)
-> Stale Closure라고도 한다 (오래된 클로져)
2. 의존성 배열 자체를 생략하는 경우
useCallback배열의 두 번째 인자를 아예 생략하는 것이다.
const function = useCallback(var1, var2)
이 구조인데, var2인 [addToast]가 없는 경우이다. 감시할 대상이 없으니, 리액트는 그냥 함수를 매번 새로 만든다.
3. [addToast]가 다른 함수로 바뀌는 겨우
useCallback은 매번 리액트가 다시 그려질 때마다 이렇게 비교한다.
지난번에 내가 봤던 `addToast`가 들어있던 메모리 주소가 `0x123`이었는데, 지금은 `0x456`이네?
아, 함수 내용이 바뀌었구나!
함수 이름이 같아도 메모리 주소(Reference)가 달라지면 리액트는 바뀌었다고 판단 -> function (위에서는 showlogs)새로만듦.
js나 리액트 법칙처럼 통용되는게 있다고 한다.
함수 안에서 쓰는 외부 변수나 함수가 있다면, 고민하지 말고 의존성 배열에 다 집어넣어라
'공부기록' 카테고리의 다른 글
| [Stock Forecasting]BackTesting in LSTM Stock Forecasting (공부기록 10일차, 240421) (2) | 2024.04.22 |
|---|---|
| [Stock Forecasting] - Backtesting.py (공부기록 8일차, 240418) (1) | 2024.04.19 |