원래 코드는 html의 <title>태그를 업데이트해주지만, 편의상 클래스로 지정했다. useEffect를 사용하여 페이지가 로드되면 title을 변경한다.
const useTtile = (initialTitle) => {
const [title, setTitle] = useState(initialTitle);
const updateTitle = () => {
const htmlTitle = document.querySelector(".title");
htmlTitle.innerText = title;
};
useEffect(updateTitle, [title]);
return setTitle;
};
updateTitle은 태그를 가져와 내용을 useState의 title로 할당한다. useEffect는 title값이 바뀌면 updateTitle를 실행한다. 최종적으로는 useState의 setTitle을 돌려준다.
const UseTitle = () => {
const titleUpdater = useTtile("Loading...");
setTimeout(() => titleUpdater("Home"), 5000);
const onRefresh = () => location.reload();
return (
<div>
<h1 className="title">UseTitle</h1>
<button onClick={onRefresh}>새로고침</button>
</div>
);
};
titleUpdater는 useTitle의 리턴값을 받아 setTitle과 같아졌다. 그렇기에 setTitmeout에서 "Home" 인자를 받을 수 있다. 새로고침 해보면 초기에 "Loading..."이 나왔다가 5초 후 "Home"으로 바뀐다.
해당 강의 댓글 목록에서 useEffect를 사용하지 않아도 기능적으로 잘 돌아간다는 댓글을 보고 따라해봤다.
기능면에서는 차이가 없고, 콘솔의 'hi' 호출에서 볼 수 있듯이 렌더링 횟수 차이가 있는 듯했다. useEffect는 deps로 title을 받았으므로, title이 변하는 2번(최초, 5초 후)만 호출했다.
반면, useEffect를 사용하지 않은 오른쪽은 4번 호출했다. 이유는 정확히 모르겠지만, 최초 1번, 5초 후 1번, 바로 렌더링 1번, 다시 5초 후 변한 값이 있는지 확인 1번이 아닐까 추측해본다. 어쨌든 낭비를 조금이라도 낭비를 막으려면 useEffect를 사용하는 게 낫겠다.
(22.02.22 추가)
Loading 중 다른 페이지로 옮기면 메모리 누수 경고가 발생한다. Loading이 완전히 끝나 타이틀이 바뀐 후에는 아무 상관 없다.
Warning: Can't perform a React state update on an unmounted component.
This is a no-op, but it indicates a memory leak in your application.
To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
참고
리액트 hook useState 문서: https://ko.reactjs.org/docs/hooks-effect.html
노마드코더 실전형 리액트 hooks: https://nomadcoders.co/react-hooks-introduction/lobby
useEffect 잘 정리된 블로그 : https://xiubindev.tistory.com/100