0. 이글을 작성하는 이유?
- useCallback과 useMemo는 언제 memorization을 하는지?
- hook api가 언제 호출되는지 확실히 말할 수 있을까?
- class Component의 life cycle이랑 비교하고 싶어서
1. useCallBack vs useMemo Memorization Timing
-
useCallback
- 주로 함수(eventHandler 등)를 새로 만들지 않고 재사용하고 싶을 때
- useCallback으로 감싼 함수를 호출할때, Memoizing
- dependency의 따라 메모리제이션 된 함수를 리턴할지, 새로운 함수를 호출할지 결정된다.
// before Memorization const memoizedCallback = useCallback(() => { doSomething(a, b) }, [a, b]) // Memoizing memoizedCallback()
-
useMemo
- 주로 특정 결과값을 재사용 하며, 기능은 useCallback이랑 같음
- useMemo는 컴포넌트 첫 렌더링시, Memoizing
- dependency에 따라 작동하는건, useCallback과 동일
- props 변경시, 컴포넌트가 새롭게 렌더링 되기 때문에, Re-Memoizing
useCallback(fn, deps)
===useMemo(() => fn, deps)
// Memorization when first Rendering const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
2. 각 상황별 이벤트 로그(테스트 코드 참고)
- 비슷한 역할을 하는 함수
constructor
===useState Callback
setState Callback
===setState Callback
shouldComponentUpdate
===React.memo
componentWillUnmount
===useEffect cleanup function
3. 테스트 코드
-
Class Component
class ClassLife extends React.Component { constructor(props) { super(props) console.log('1. constructor') } state = { number: 0, } shouldComponentUpdate(nextProps, nextState) { console.log('1-2 shouldComponentUpdate') return this.state.number !== nextState.number } componentDidUpdate(prevProps, prevState, snapshot) { console.log('3. componentDidUpdate') } componentDidMount() { console.log('4. componentDidMount') } componentWillUnmount() { console.log('5. componentWillUnmount') } handleClick = () => { console.log('1. handleClick') this.setState((prev) => { console.log('1-1-1. in setState') return { ...prev, number: this.state.number + 1, } }) } handleEqual = () => { this.setState({ number: this.state.number, }) } handleToggle = () => { this.props.onrr() } render() { console.log('2. render') return ( <div> <h1> Class Component</h1> <button onClick={this.handleClick}>UpdateState</button> <button onClick={this.handleEqual}>Equal</button> <button onClick={this.handleToggle}>handleToggle</button> <div>number: {this.state.number}</div> </div> ) } }
-
Function Component
const FunctionLife = (props) => { console.log('function component body first line') const [number, setNumber] = React.useState(() => { console.log('callback in useState') return 0 }) React.useEffect(() => { console.log('function in useEffect Callback noDependency') return () => { console.log('function in useEffect Callback dependency') } }, []) React.useEffect(() => { console.log('function in useEffect Callback dependency') return () => { console.log('cleanup function in useEffect dependency') } }, [number]) const updateState = (foo) => { console.log('foo', foo) setNumber((prev) => { console.log('callback in setState') return prev + 1 }) } const updateStateUseCallback = React.useCallback(() => { console.log('function body in useCallback') updateState('useCallback') return () => { console.log('return updateStateUseCallback') } }, []) const updateStateUseMemo = React.useMemo(() => { console.log('callback in useMemo') return updateState }, []) const updateEqual = () => { setNumber((prev) => prev) } return ( <div> <h1>FunctionLife</h1> <button onClick={updateState}>updateState</button> <button onClick={updateEqual}>updateEqual</button> <button onClick={updateStateUseCallback}> updateStateUseCallback </button> <button onClick={updateStateUseMemo}>updateStateUseMemo</button> <button onClick={updateStateUseMemo}>updateStateUseMemo</button> <h3>{number}</h3> </div> ) } export default React.memo(FunctionLife, (prev, next) => { console.log('callback in React memo') return JSON.stringify(prev) === JSON.stringify(next) })