useEffect(() => { //componentDidMount, componentDidUpdate역할
interval.current = setInterbal(changeHand, 100)
return () => { // componentWillUnmount 역할
clearInterval(interval.current)
}
}, [imgCoord]) //이 값이 바뀔때 useEffect가 실행 (deps라고 한다)
처음 컴포넌트가 렌더링 되고 난 후, deps에 값이 바뀔 때마다 실행된다. (componentDidMount, componentDidUpdate역할)
return문에 실행 시점은 deps안에 값이 바뀌기 전에 실행된다.
또한 컴포넌트가 사라질 때 실행된다.
interval, timeout 사용 시 항상 clear Interval, timeout을 return 안에서 해줘야한다.
props의 값이나 state값을 사용하고 있다면 항상 deps안에 넣어주어야한다.
deps안에 실행 조건을 넣어줄 수 있다
예 )
useEffect(() => {}, [balls.length === 0])
//balls.length === 0일때만 실행
또는 바뀌는 시점을 넣어준다
useEffect(() => {}, [timeouts.current])
// timeouts가 바뀔때마다 실행
주의할 점
배열의 요소로 넣어주는 것은 바뀌는게 아니다
예) array[i] = 값
-> 배열의 요소로 값을 넣어주는 것이기 때문에 바뀌는 것이 아니다
arrya = []
-> 배열을 넣어주는 것이기 때문에 바뀌는 것이다.(react가 감지함)
컴포넌트 전체에서 useEffect가 실행된다.(어떤 동작을 하던지 전부 실행됨)
부모 컴포넌트가 실행되면 자식 컴포넌트도 실행되기 때문이다.
가상 DOM에서만 변경이 일어나고 실제 DOM은 바뀐 부분만 변경이 일어난다.
useEffect안에서 비동기 처리는 함수로 따로 분리하자
화면 크기 늘렸다 줄였다 (화면 resizing) 하기 전에 발생
화면 layout변화를 감지할 때
useEffect : 화면이 완전히 바뀌고 난 후 발생
useLayoutEffect: 화면 바뀌기 전 발생(화면바뀌는 것을 감지)
함수 자체를 기억
렌더링 될 때 함수 자체가 재시작 돼도 함수가 새로 만들어지지 않는다.
자식 컴포넌트에게 메서드를 전달할 때에는 useCallBack으로 감싸서 전달할 때마다 메서드가 새로 생성되지 않도록 한다.
이전 state 값을 계속 기억하기 있기 때문에 함수 안에서 사용하는 state 혹은 props 가 있다면 꼭, deps 배열안에 포함시켜야 된다.
컴포넌트에서 props 가 바뀌지 않았으면 Virtual DOM 에 새로 렌더링하는 것 조차 하지 않고 컴포넌트의 결과물을 재사용 하는 최적화 작업을 할 때, 이 작업을 하려면 함수를 재사용하는것이 필수다.
함수를 useCallBack으로 감싸준다 하더라도 deps에 state값이 있다면 값이 바뀔때마다 함수가 새로 만들어진다. 때문에 하위 컴포넌트의 전체가리렌더링이 일어난다. (예 : userList에서 list를 새로 등록시, 기존 list도 전부 다시 렌더링이 된다.)
deps 에서 참조하고 있던 상태값을 지우고, 함수들에서 현재 useState 로 관리하는 상태값을 참조하지 않게 한다. 즉 함수형 업데이트를 한다.
setState의 콜백함수의 파라미터에서 최신 상태값을 참조 할 수 있기 때문에 deps 에 상태값을 넣지 않아도 된다.
예 : setUsers(prevUsers => prevUsers.concat(user))
React.memo 에서 두번째 파라미터에 propsAreEqual 이라는 함수를 사용하여 특정 값들만 비교를 하는 것도 가능하다.
export default React.memo(
UserList,
(prevProps, nextProps) => prevProps.users === nextProps.users
);
하지만 함수형 업데이트로 전환을 안했는데 이렇게 users 만 비교를 하게 된다면, 나머지 props에서 최신 상태값을 참조하지 않으므로 심각한 오류가 발생 할 수도 있다.