유데미 강의를 듣고 실습한 내용 정리하기
최초 마운트에는 실행하지 않는 커스텀 useEffect만들기
클릭 하면 클릭 횟수(초록 동그라미), 전체 카운트(회색 글씨)가 각각 1씩 증가되고 클릭 애니메이션이 나타나는 컴포넌트를 제작한다.
버튼 클릭하면 카운트들이 +1회 증가므로 카운트 값이 변경되면 애니메이션을 실행시켜 주는 함수를 실행하도록 한다.
useEffect(()=>{
//애니메이션 함수 실행
},[count])
그런데 문제가 생긴다.
버튼을 클릭 해야만 애니메이션이 실행되어야 하는데 useEffect는 최초 마운트시에도 useEffect안의 내용이실행되기 때문이다.
따라서 단순이 페이지를 로딩했을 뿐인데 애니메이션이 실행 되어버린다.
이를 해결하기 위해서 변수를 하나 두어서 컴포넌트가 마운틴 된 상태인지 체크할 수 있다.
const componentJustMounted = useRef(true);
useEffect(() => {
if (!componentJustMounted.current) {
// 애니메이션 함수 실행
}
componentJustMounted.current = false;
}, [count]);
처음 컴포넌트가 마운트 되었을 때는 componentJustMounted
값이 true이므로 애니메이션 함수를 실행시키지 않는다.
그 후 componentJustMounted
를 false로 변경한다.
그 다음번에 불려지는 useEffect를 실행 할 땐 애니메이션 함수를 수행할 수 있게 된다.
이 로직을 컴포넌트 내부가 아닌 밖으로 빼서 음 마운트 됐을 땐 실행되지 않도록 하는 custom hook을 만들 수 있다.
const useEffectAfterMount = (cb, deps) => {
const componentJustMounted = useRef(true);
useEffect(() => {
if (!componentJustMounted.current) {
return cb();
}
componentJustMounted.current = false;
}, deps);
};
useEffectAfterMount(() => {
animationTimeline.replay(); // 애니메이션 실행 함수
}, [count]);
최초 마운트시에는 실행되지 않고, 그 이후 변경값이 있을때만 effect를 실행시키도록 하는 useEffectAfterMount
커스텀 훅을 만들어서
해당 훅이 필요한 곳에서 사용한다.
count, totalCount 상태를 담고있는 custom hook 만들기
const INITIAL_STATE = {
count: 0,
countTotal: 267,
isClicked: false,
};
const useClapState = (initialState = INITIAL_STATE) => {
const MAXIMUM_USER_CLAP = 50;
const [clapState, setClapState] = useState(initialState);
const { count, countTotal } = clapState;
const updateClapState = useCallback(() => {
setClapState(({ count, countTotal }) => ({
isClicked: true,
count: Math.min(count + 1, MAXIMUM_USER_CLAP),
countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal,
}));
}, [count, countTotal]);
return [clapState, updateClapState];
};
카운트 들의 상태와 이를 변경하는 setState 함수를 내부에 넣은 custom 훅을 만든다.
이후 다른 컴포넌트에서 이 커스텀 훅을 사용하여 업데이트 함수를 실행실 수 있다.
const [clapState, updateClapState] = useClapState();
...
<button
onClick={updateClapState}
>
...
여러개의 ref를 갖고 있는 커스텀 훅 만들기
여러개의 DOM 엘리먼트에 ref를 저장해두는 state가 필요하다.
ref를 연결할 요소에 엘리먼트를 구분할 data-refkey속성을 넣는다.
<button data-refkey ="clapRef">
...
<span data-refkey ="clapCountRef">
...
<span data-refkey ="clapTotalRef">
해당 엘리먼트들에 ref를 연결해 하나의 state에 저장한다.
<button data-refkey ="clapRef" ref={setRef}>
...
<span data-refkey ="clapCountRef" ref={setRef}>
...
<span data-refkey ="clapTotalRef" ref={setRef}>
const [{ clapRef, clapCountRef, clapTotalRef }, setRefsState] = useState({});
const setRef = useCallback((node) => {
//save the node\
setRefsState((prevRefstate) => ({
...prevRefstate,
[node.dataset.refkey]: node,
}));
}, []);