강의 유튜브 주소 :

https://www.youtube.com/watch?v=V3QsSrldHqI&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn

 

 

Hooks에 관한 자잘한 팁들

use 시리즈들은 순서가 매우매우 중요해서 중간에 바뀌면 안된다.

const Test = () => {

    const [number, setNumber] = useState(); // 1
    const [string, useString] = useState(); // 2

 

조건문을 통해 생성의 여부를 결정하면 매우 위험하다.

const Test = () => {

    const [number, setNumber] = useState(); // 1
    const [string, useString] = useState(); // 2

    if(조건){
        const [array, setArray] = useState(); // 3
    }

    const [name, setName] = useState(); // 4

왜냐하면 위에 말했듯이 실행순서가 같아야하는데 조건문에 따라 실행순서가 달라질 수 있기 때문이다.

만약 조건에 따라서 4번인 변수가 3번이 되어버린다면 문제가 된다.

조건문 안에 넣으면 안된다.

그리고 반복문, 함수 안에도 최대한 넣지 않아야한다. (순서가 정말 확실한 반복문은 해도되나 추천하지 않는다)

그리고 최상위에 선언하는것이 좋다.

 

다른 useEffect안에서도 useState를 쓰면 안된다.

useEffect 내부에서 useState의 실행순서가 확실하지 않기 때문이다.

useEffect(() => {
    useState(); // (X)

 

아 그리고 ajax호출은 보통 componentDidMount에서 많이 하는데, 이것을 hooks에서 하고싶을때

useEffect에서 componentDidMount를 하는 기능을 흉내내야한다고 하면 

따로 useEffect를 생성해서 componentDidMount기능을 하도록 하면 된다.

2번째 인자는 빈배열!

useEffect(() => {
	// ...
}, []);

 

componentDidMount에서 안하고 componentDidUpdate나 다른 라이프 사이클에서 실행하고 싶을떄가 좀 까다롭다고 한다.

패턴으로 기억해두는게 좋다고 한다.

const mounted = useRef(false);

// componentDidUpdate만 하는법!!, componentDidUpdate에서는 안함
useEffect(() => {
    if(!moounted.current){
        mounted.current = true;
    }else {
        // ajax
    }
});
const flag = false;

useEffect(() => {
    if(!flag){
        flag = true;
    }else{
        // ajax    
    }
});

 

강의 유튜브 주소 :

https://www.youtube.com/watch?v=V3QsSrldHqI&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn



useMemo와 useCallback

Class에서 작업했던 것들을 Hooks로 옮기다보면 Class에서 문제가 되지 않던 부분들이 문제가 되는 경우가 있다.

Hooks는 함수안에 있는 내용이 재 렌더링이 되는데, 

getNumbers라는 함수가 Hooks의 특성으로 인해서 재 렌더링이될 수 있다.

import React, { useState, useRef, useEffect } from 'react';

function getNumbers(){
    // ......
}

const Test = () => {
    const numbers =() => getWinNumbers(

    );

    // .....

이때 getNumbers가 캐싱될 수 있도록 useMemo를 써주는게 좋다.

import React, { useState, useRef, useEffect } from 'react';

function getNumbers(){
    // ......
}

const Test = () => {
    const numbers = useMemo(() => getNumbers(

    ), [ state ]);

    // .....

 

useEffect와 같이 useMemo나 useCallback에도 두번째 인자값을 넣을 수 있다.

두번째 인자값이 바뀌면 재렌더링이되고 그렇지 않다면 재렌더링이 되지 않는다.

위와 같이 useMemo를 썼을 경우 (useMemo처럼 한번 더 함수를 감싸면 high order component가 된다, hoc)

getNumbers를 캐싱한다.

요소가 바뀌기 전까지는 캐싱한 값을 가져온다.

 

useCallback과 useMemo를 헷갈려하는 경우가 많다는데,

useMemo는 값을 기억하는 것이다.

리턴값. 즉 getNumbers에서 넘어오는 number값을 기억한다.

useCallback은 함수자체를 캐싱하는 것이다.

이벤트 핸들러같은것을 캐싱할 수 있다.

const onClickRedo = useCallback(() => {
    // ....
}, []);

 

함수의 비용이 클때 사용한다.

그렇다면 함수마다 useCallback을 쓰면 이득인가? 생각할 수 있다는데, 이것은 반반이다.

useCallback을 모든 함수에 감쌀 경우 첫번째 동작은 늘 같을 수 있다.

하지만 문제가 캐싱을 너무 잘해서 값이 바뀌었을 경우 인식하지 못하는 경우라고 한다.

그래서 useCallback을 쓸때 두번째 인자값에 유의해야한다.

두번째 인자값역시 useEffect나 useMemo와 같이 재렌더링을 하려고하는 state나 props, 그리고 조건문을 넣으면 된다고 한다.

const onClickRedo = useCallback(() => {
    // ....
}, [ state ]);

 

useEffect, useMemo, useCallback모두 빈배열이 default값이다.

 

아 그리고 useCallback을 필수로 적용해야하는 경우가 있는데, 자식 컴포넌트에 props를 함수로 넘기는 경우 useCallback을 필수로 적용해줘야한다고 한다.

매번 새로운 함수가 랜더링되면 비용이 크기때문에 자식컴포넌트에 넘기는 함수에 적용하도록 하자.

그래서 부모로 부터 전달받는 함수가 매번 같을 경우 재 렌더링이 일어나는 것을 방지해줘야한다.

// onClick 함수에 useCallback을 적용한다
const onClick = useCallback(() => {
    // ....
}, [ state ]);

// ....
<Test number={props} onClick={onClick} />

 

강의 유튜브 주소 :

https://www.youtube.com/watch?v=V3QsSrldHqI&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn

 

 

useEffect로 업데이트를 감지할 수 있다.

재 렌더링이슈가 없기때문에 state나 props를 쓰지 않으면 앞에서도 말했듯이 일반 함수로 생성하는 것이 좋다.

 

componentDidUpdate가 될때 hooks(useEffect)로 변경할때 힘든 부분이 성능문제다.

useEffect는 1:1로 대응되는 것이 아니기 때문이다.

import React, { useState, useRef, useEffect } from 'react';

const Lotto = () => {
    const [numbers, setNumbers] = useState(getNumbers());
        const timeouts = useRef([]);    
    
    useEffect(() => {
        //.......... 
    }, []);

    setNumbers(getNumbers());
    timeouts.current = [];
    
    return (
        <div>
        	// ....
        </div>
    );
}

useEffect의 두번째인자가 빈 배열일 경우에는 componentDidMount와 동일하게 동작한다.

만약 componentDidUpdate를 하고 싶다면 두번째인자값에 state나 props를 넣어서 해당 state나 props가 변경되었을때 재 렌더링이 될 수 있도록(호출) 해주면 된다.

이때 componentDidMount의 기능과도 같아진다.

 

return 하는 것이 componentWillUnMount의 기능이다.

const Lotto = () => {
    const [numbers, setNumbers] = useState(getNumbers());
        const timeouts = useRef([]);    
    
    useEffect(() => {
        //.......... 

        return () => { 

            // return 할때 componentWillUnMount와 같다.
            };
    }, []);

    setNumbers(getNumbers());
    timeouts.current = [];
    
    return (
        <div>
        	// ...
        </div>
    );
}

 

componentDidUpdate를 할때 어떤것을 두번째 인자로 넣어야하는가?

조건문은 넣어도 될까?

두번째 인자값은 꼭 state일 필요가 없다.

조건문을 삽입해도 동작한다.

useEffect(() => {
        //.......... 

        return () => { 

            // return 하는 것이 componentWillUnMount
            };
    }, [ win.lenght === 0]);

 

componentDidUpdate와 useEffect는 완벽히 일치할 수 없다.

흉내내기로 보는것이 좋다.

강의 유튜브 주소 :

https://www.youtube.com/watch?v=V3QsSrldHqI&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn

 

 

// 고차함수

this.onClick = (arg) => (e) => {
	//	...
}

render(){
	return(
		<button onClick={this.onClick()}>
    );
}

(arg) => 뒤에 arrow function을 추가해서 감싸줄 수 있다.

 

여러번 setState를 호출해도 한번만 렌더링한다.

이것은 react가 알아서 처리한다.

setState({})
setState({})
setState({})
setState({})
setState({})

 

class 컴포넌트에서 라이프사이클을 쓸 수 있는데 함수컴포넌트에서는 어떻게쓰는가?

componentDidMount, componentDidUpdate, componentWillunMount를 useEffect로 흉내낼 수 있다.

각각의 역할이 1:1로 대응이 되는건 아니고 useEffect하나로 한번에 흉내낼 수 있다. (각각쓸수도 있다)

// 선언
import React, {useEffect} from 'react';

const Test = () => {

    //...

	//componentDidMount, componentDidUpdate 역할을 동시에 함(1:1 아님)
    useEffect(() => { 

		// componentDidMount, componentDidUpdate 때 적용할 코드를 적으면 된다.
        // ....
    
    	// componentWillunMount 때 적용할 코드를 적으면 된다.
        return () => { 
            // ....
        }       

    // 2.여기에넣는 인자값에 변화가 있을때 useEffect가 다시 실행된다.
    }, [imgCoord]);
}

첫번째가 실행될 함수고 두번째는 인자값은 state를 넣어주는데, 이 인자값에 변화가 있을때마다 useEffect가 실행된다.

그래서 완벽히 똑같지 않고 라이프사이클을 흉내낸다고한다.

 

만약 아무것도 넣지 않았을 경우에는 딱 한번만 실행된다. (componentDidMount)

import React, {useEffect} from 'react';

const Test = () => {
    useEffect(() => { 
        return () => { 
            // ....
        }       
    }, []);
}

 

또 useEffect는 여러개를 사용할 수 있다.

각각의 state의 변화에 따라 동작이 다를 경우를 예로 들어본다.

import React, {useEffect} from 'react';

const Test = () => {
    useEffect(() => { 
        return () => { 
            // ....
        }       
    }, [value]);
    
    useEffect(() => { 
        return () => { 
            // ....
        }       
    }, [code]);
}

(만약 class컴포넌트에서 여러개를 사용하고자하면 라이프사이클안에서 조건문을 활용하면된다)

 

pureComponent와 같이 얕은 객체를 비교해주는게 있는데 함수형컴포넌트에서는 memo를 사용해준다.

import React, { memo } from 'react';

const RES = memo(() => {

 

useLayoutEffect도 있는데, 이건 화면 렌더링이 끝나고 실행된다고 한다.

resizing이 끝나고 나서 화면(layout)이 바뀌는 것을 감지할때 쓴다.

사용법은 useEffect와 동일하다. 

(완전히 바뀌고 나서 실행할 것인지에 대해 생각하고 사용한다)

 

아 그리고 setInterval, setTimeout을 사용할 경우 render안에서 사용하면 안되고 

componentWillunMount에서 clearInterval, clearTimeout을 꼭해줘야한다.

부모컴포넌트에서 자식컴포넌트를 삭제할때를 대비해서 해줘야한다.

해주지 않을 경우 계속 메모리상에서 실행되고 있다.(setState에 귀속되고 있기 때문에 제거!)

 

보통 컴포넌트를 어떻게 쪼개나? 할때 반복문을 기점으로 쪼개는 경우가 많다.

자식컴포넌트로 넘기는 데이터가 없는 경우에는 pureComponent로 만들어서 재렌더링이 되는 것을 방지하자.

혹은 데이터가 필요없으면 일반 함수 컴포넌트로 만든다. 그후 memo를 통해 최적화한다. 

memo로 감싸주면 hoc가 된다.(high order component)

(최적화할때 확인하고 재렌더링이 필요없는데 일어날경우 처리해준다)

 

그리고 componentWillReceiveProps, willMount, willUpdate는 곧 없어질 예정이니 사용하지 말라고한다.

will시리즈는 willunMount를 제외하고는 사라질 예정이라고한다.

 

componentDidUpdate는 state나 props 변화가 생겼을때 비교를 통해 재렌더링을 할지 말지를 결정할 수 있다.

return값이 true일 경우 재 렌더링을 한다.

componentDidUpdate(prevProps, prevState) {
  // prevState는 변하기 전 state의 값, this.state는 변화된 현재의 state값
  if (this.state.id !== prevState.id) {
		return true;
  }
}

 

+ Recent posts