React Hooks 사용하기(3)_useCallback, useRef

호박쿵야·2021년 12월 2일
0

react

목록 보기
3/7
post-thumbnail

useCallback

useCallback은 useMemo와 상당히 비슷하다. (이전 포스팅 참고) 주로 렌더링 성능을 최적화해야 하는 상황에서 사용하다. useCallback을 통해 이벤트 핸들러 함수를 필요할 때만 생성할 수 있다.

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

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

    const onChange =(e)=>{
        setNumber(e.target.value)
    }
    const onInsert = (e)=>{
        const newList = list.concat(parseInt(number))
        setList(newList)
        setNumber('')
    }

    const avg = useMemo(()=> getAverage(list), [list])
    return(
        <div>
            <input value ={number} onChange ={onChange}/>
            <button onClick={onInsert}> 등록 </button>
            <ul>
                {list.map((value, index) => 
                    <li key={index}>{value}</li>
                )}
            </ul>
            <div>
                <b>평균 값 : </b>{avg}
            </div>
        </div>
    )
}

Average 컴포넌트 내부에는 이벤트 핸들러로 onChange와 onInsert가 선언되어 있다. 이벤트 핸들러는 컴포넌트가 리렌더링 될 때마다 새로 생성되는데, 컴포넌트의 렌더링이 자주 발생하거나 렌더링해야 할 컴포넌트의 개수가 많을 경우 이 부분을 최적화 해주는 것이 좋다.

👉 useCallback을 이용한 최적화

	...
    const onChange =useCallback((e)=>{
        setNumber(e.target.value)
    },[])
    const onInsert = useCallback((e)=>{
        const newList = list.concat(parseInt(number))
        setList(newList)
        setNumber('')
    },[number, list])
	...

useCallback의 첫번째 파라미터에는 생성하고 싶은 함수를 넣고, 두번째 파라미터에는 배열을 넣는다. onChang()처럼 컴포넌트가 처음 렌더링될 때만 함수를 생성하려면 [ ] 빈 배열을 넣는다. onInsert()와 같이 어떤 값이 변경될 때만 생성하도록 하려면 [number, list]처럼 배열에 변경을 체크할 값을 넣어주면된다. number와 list의 값이 바뀌거나 새로운 항목이 추가될 때 마다 함수가 생성된다.

함수 내부에서 상태 값에 의존해야 할 때는 그 값을 반드시 두 번째 파라미터 안에 포함시켜 주어야한다. onChange()의 경우 기존의 값을 조회하지 않고 설정하는 기능만 하기 때문에 빈 배열을 넣어줬지만, onInsert()는 기존의 number와 list를 조회해서 newList를 생성하기 때문에 꼭 두 번째 파라미터 배열안에 넣어줘야한다.

숫자, 문자열, 객체처럼 일반 값을 재사용하려면 useMemo를 사용하고, 함수를 재사용하려면 useCallback을 사용한다.

👉 같은 기능을 담은 코드 비교 useCallback vs useMemo

useCallback(()=>{
    console.log('hello pumpkin')
},[])

useMemo(()=>{
    const hello=()=>{
        console.log('hello pumpkin')
    }
    return hello
},[])

useRef

useRef는 함수형 컴포넌트에서 ref를 쉽게 사용할 수 있도록 해 준다. Average 컴포넌트에서 '등록' 버튼을 눌렀을 때 포커스가 input으로 넘어가도록 코드를 작성해보자.

const getAverage =numbers =>{
    ...
}

const Average = ()=>{
    const [list, setList] = useState([]);
    const [number, setNumber] = useState('');
    //useRef 추가한 부분 
  	const inputElement = useRef(null)
    const onChange =useCallback((e)=>{
        setNumber(e.target.value)
    },[])
    const onInsert = useCallback((e)=>{
        const newList = list.concat(parseInt(number))
        setList(newList)
        setNumber('')
		//실제 엘리먼트에 focus전달
        inputElement.current.focus()
    },[number, list])
	
    const avg = useMemo(()=> getAverage(list), [list])
    return(
        <div>
      		//input ref 확인
            <input value ={number} onChange ={onChange} ref={inputElement}/>
            <button onClick={onInsert}> 등록 </button>
            <ul>
                {list.map((value, index) => 
                    <li key={index}>{value}</li>
                )}
            </ul>
            <div>
                <b>평균 값 : </b>{avg}
            </div>
        </div>
    )
}

useRef를 사용하여 ref를 설정하면 useRef를 통해 만든 객체 안의 current 값이 실제 엘리먼트를 가리킨다.

useRef로 로컬 변수 사용하기

로컬 변수란 렌더링과 상관없이 바뀔 수 있는 값을 의미한다.
클래스형 컴포넌트

class Component extends Component{
    id = 1;
    setId =(n)=>{
        this.id = n
    }
    printId=()=>{
        console.log(this.id)
    }
}

함수형 컴포넌트 + useRef

const RefSample =()=>{
    const id = useRef(1);
    const setId =(n)=>{
        id.current = n;
    }
    const printId =()=>{
        console.log(id.current)
    }
}

💥 주의_ ref 안의 값이 바뀌어도 컴포넌트가 렌더링되지 않기 때문에 렌더링과 관련되지 않은 값을 관리할 때만 사용해주어야 한다.







🧸✨ 이 포스팅은 '리액트를 다루는 기술' 책을 기반으로 공부한 내용을 정리한 내용입니다.

0개의 댓글