컴포넌트 내부에 함수선언은 왜 하는가?

함수가 컴포넌트 내부의 state 같은 함수 외부의 값을 의존적으로 가져다 사용해야 되거나 그 값을 변화시켜야 할 때, 컴포넌트 내부에 함수 선언을 한다. (대부분의 컴포넌트 내부의 State를 이용하는 이벤트 헨들링 함수)

이때 컴포넌트가 리렌더 될 경우 매번 새로 함수를 생성되게 되는데 이를 방지하고자 메모이제이션 하기 위해 useCallback Hook을 사용한다.

컴포넌트에서 이용되는 함수의 재생성을 막고 싶다.

함수를 외부(컴포넌트 외부)에 두고 가져다쓰면 하나의 static 함수를 생성만 하게 되어서 컴포넌트 리렌더의 경우 재생성을 하지는 않는다.

함수 재생성을 막기 위해 함수를 외부에 두고 jsx 내부의 이벤트 핸들링 함수로 이용하려 한다고 해도 결국 jsx 안에서 콜백함수로 재선언을 해줘야하기 때문에 재생성을 막기 위해서는 메모이제이션 함수를 사용해야 한다.

import React, { useState, useMemo, useCallback } from 'react';

const getAverage = (numbers) => {
	console.log('평균값 계산중...');
	if(!numbers.length) return 0;
	const sum = numbers.reduce((prev, curr) => prev + curr);
	return sum / numbers.length;
}

export default function Average() {
	const [list, setList] = useState([]);
	const [number, setNumber] = useState('');

	*// 이벤트 핸들링 함수인 onChange와 onInsert 모두 컴포넌트 안의 state에 의존적이다.*
	const onChange = useCallback((e) => {
		setNumber(e.target.value);
	}), []); *// 컴포넌트가 처음 렌더링 될 때만 함수 생성*

	const onInsert = useCallback(() => {
		const nextList = [...list, parseInt(number)];
		setList(nextList);
		setNumber('');
	}), [number, list]); // number 혹은 list 가 바뀌었을 때만 함수 생성

	const avg = useMemo(() => getAverage(list), [list]);

	*// 재생성을 막고싶어서 외부함수로 호출하여 계산에 필요한 값을 파라미터로 전달한다 하더라도
	// 컴포넌트 내부에서 callback 생성을 새로 하는 경우가 많기에
	// 결국 다시 함수 선언을 하게되어서 재생성을 방지하기 위해 외부에서 함수를 불러오는 의미가
	// 없을 수 있다.

	// > 그래서 callback을 이용하고 리렌더시 재생성을 피하고 싶다면 메모이제이션 함수를 사용한다.*

	return (
		<div>
			<input value={number} onChange={onChange}/>
			<button onClick={onInsert}>제출</button>
			<ul>
				{list.map((num, idx) => (
					<li key={idx}>{num}</li>
				))}
			</ul>
			<div>
				<b>평균값:</b> {avg}
			</div>
		</div>
	);
};