저번 state와 event 문제 실습에 이어서
리액트의 주요 hook인 useState, useEffect, useRef 훅을
실습해보는 문제를 풀어보았다.
useEffect를 잘못 사용하여 무한렌더링이 되는 문제점을 찾아서
따로 useEffect를 사용할 때, 이러한 실수를 하지 않도록 알아보았다.
또한, useRef를 통해 리렌더링이 되지 않아도 되는 부분이
리렌더링이 되는것을 막을 수 있다.
문제 1. useState()를 사용하여 다음과 같은 결과가 출력되도록 해보시오.
1번 코드 풀이
먼저, 변수를 저장할 상태 eating을 초기화.
input에서 onChange 이벤트가 발생할 때 value값을 담을 상태 value를 초기화.
inputHandler 함수를 정의.
input에서 onChange 이벤트가 발생하면 setValue 함수를 호출하여
value값을 변경시키고, 이 inputHandler 함수를 input 태그의 onChange 함수에 넣어줌.
clickHandler 함수를 정의.
"추가" 버튼을 눌러 클릭 이벤트가 발생하면 setState 함수를 호출하여
value 값이 기존 eating 상태값보다 선행하는 새 배열을 eating에 재할당
문제 2. useEffect()를 이용하여 다음과 같은 결과를 출력하는 코드를 작성하세요.
조건
- '렌더링 완료' 최초 한번만 출력
- 버튼 클릭 시, 콘솔에 "count 값이 바뀜" 출력
- text 입력 시, 콘솔에 "input 값이 바뀜" 출력
2번 코드 풀이
count와 text를 state로 초기화
input에 입력했을 때, text값이 변경되도록 inputHandler 함수를 만들고,
input 태그에 inputHandler함수를 onChange이벤트에 넣어줌.
버튼을 클릭했을 때, count를 +1을 해주는 countHandler 함수를 만들고,
button 태그에 countHandler함수를 onClick이벤트에 넣어준다.
화면이 마운팅됐을때 콘솔에 "렌더링 완료"가 출력되기 위해서
useEffect 함수를 호출함.
useEffect함수는 첫번째 인자에 콜백함수를 넣음. 콜백함수 안에는 출력하고 싶은 "렌더링 완료"를 넣어줌.
두번째 인자에는 빈 대괄호[] 를 넣어서 처음 랜더링 될때 콜백함수가 한번 실행되도록 함.
문제 3. useEffect()를 사용하여 렌더링 횟수를 출력하는 프로그램을 만들어보세요.
다음 아래의 코드에는 문제점이 있다. 그 점을 수정해보자
문제점이 있는 코드
위의 코드를 실행해보면 다음과 같이 무한으로 렌더링이 되는 버그가 발생한다.
왜그런 것일까??
- 위의 문제가 있는 코드를 보면, useEffect() 함수에서 두번째 인자로 []를 넣지않았다.
따라서, 리렌더링이 되었을 때 useEffect()함수안의 콜백함수가 재실행된다. - 지금 useEffect() 함수안의 첫번째 인자로 setRenderCount() 함수가 호출된다.
호출되면, 페이지가 리렌더링이 된다. - 리렌더링이 되면 또다시 useEffect() 함수가 실행이 되고, 그러면 또
useEffect()함수의 콜백함수인 setRenderCount()함수가 재호출된다. - 즉, useEffect()호출 -> setRenderCount()호출 -> useEffect()호출 -> setRenderCount()호출 ...
이 과정이 무한으로 반복되어 무한 렌더링이 되는 버그가 발생되는 것이다.
따라서 이런 버그를 방지하기 위한 코드를 짜야한다.
수정된 코드
3번 코드 풀이
useEffect() 함수의 두번째 인자로 대괄호를 넣어준다.
대괄호 안에 count를 넣어서 이 값이 바뀔 때만 useEffect() 함수 안의 콜백함수가 재실행 되도록 한다.
그러면 버튼을 클릭할 때만 count값이 변경되어 useEffect()함수 안의 콜백함수가 실행된다.
즉, useEffect()함수의 두번째 인자로 [count]를 넣어줌으로써
count값이 변경될때만 렌더링을 하게해주어 무한으로 렌더링되는 것을 막았다.
문제 4. 다음 조건에 맞게 프로그램을 수정하세요.
조건 :
- 실행 결과를 보면 입력창에 변화가 발생할 때마다 불필요한 재렌더링을 하고 있다.
- useRef()를 이용하여, 전송 버튼을 눌렀을 때만 렌더링이 되도록 수정
4번 코드 풀이
useRef()를 사용하면 input 태그에서 change 이벤트가 발생했을 때
state값이 변경되어서 페이지가 리렌더링 되는 것을 막을 수 있다.
먼저 text 상태값을 초기화한다.
useRef()를 이용하여 textRef 변수를 초기화한다.
inputHandler 함수를 생성한다.
• 이 함수는 입력 이벤트가 발생했을 때 textRef.current 값이 동일하게 변경된다.
• useRef()로 할당한 변수는 값이 바뀌어도 리렌더링이 되지 않는다.
• input의 onChange이벤트에 inputHandler 함수를 넣어준다.
clickHandler 함수를 생성한다.
• 클릭 이벤트가 발생하면 setText()함수를 호출한다.
• 인자로 textRef.current를 넣어준다.
• button 태그의 onClick 이벤트에 clickHandler 함수를 넣어준다.
input 태그에 입력값이 들어가도 useRef()를 이용해
변수 값이 바뀌기 때문에 페이지는 리렌더링이 되지않는다.
버튼을 누를때 setText()함수를 호출하면서 리렌더링이 발생하게 되면서,
textRef값이 그때 화면에 보이게 된다.
오늘 이 문제들을 풀어보면서 요약된 점
useEffect를 사용할때 첫번째 인자로 콜백함수를 넣고,
두번째 인자를 비워두면 , 페이지가 렌더링 될 때 콜백함수가 계속해서 호출된다는 것을 배웠다.
위와 같은 이유로 잘못하면 렌더링이 무한으로 발생되는 문제점이 생길 수 있으니
가급적이면 두번째 인자에 대괄호를 넣어서 페이지가 렌더링 되었을때
한번만 콜백함수가 호출되도록 한다.
만약 특정한값이 바뀔때만 콜백함수가 호출되게 하고 싶다면,
useEffect() 두번째 인자로 [특정한 값]을 넣어준다.
useRef를 사용해서 변수를 만들면, 이 변수의 값이 직접적으로 변경되어도
페이지가 리렌더링 되지 않는다.