본문 바로가기
개발 관련 개념들

[React.js] useEffect 더 잘 사용하기

by 코곰 2021. 5. 1.

리액트 훅에서 useEffect는 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 해주는 Hook이다.

 

class형 life cycle methods로 생각하면 componentDidMount + componentDidUpdate + componentWillUnmount 가 합쳐진 거라고 생각할 수 있다.

 

ko.reactjs.org/docs/hooks-effect.html

 

Using the Effect Hook – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

다양한 사용 케이스

참고 ↓

stackoverflow.com/questions/53070970/infinite-loop-in-useeffect#

 

Infinite loop in useEffect

I've been playing around with the new hook system in React 16.7-alpha and get stuck in an infinite loop in useEffect when the state I'm handling is an object or array. First, I use useState and in...

stackoverflow.com

1. 현재 / 부모 컴포넌트가 리렌더링 될 때마다 실행

useEffect(() => {
    // don't know where it can be used :/
    // 사용될 경우가 어디 있을까나?
})
  • 기본적 형태로 함수를 호출하면 현재 / 부모 컴포넌트가 리렌더링될 때마다 실행됨!
  • 어떤 사용법이 있을 진 잘 모르겠다

2. 현재 컴포넌트가 맨 처음 마운트 (렌더링) 될 때만 실행

useEffect(() => {
    // do anything only one time if you pass empty array []
    // keep in mind, that component will be rendered one time (with default values) before we get here
  }, [] )

 

  • useEffect 함수의 두 번째 파라미터로 [] 빈 배열을 넣어주면,
  • 현재 컴포넌트가 맨 처음 마운트 (렌더링) 될 때 실행된다.

 

  • 이 때 중요한 점은, 컴포넌트가 마운트된 직후 useEffect 함수가 실행되기 때문에,
  • useEffect 함수 실행 없이도 나머지 코드가 에러를 내지 않도록 설계하는 것이 필요하다.

============================================================

예시

  • 내 프로젝트의 댓글 보여주기 컴포넌트의 경우,
  • 댓글이 추가되거나 삭제될 때마다, 서버에 요청을 보내 댓글 목록을 새로 받아와야 했다.
    • 서버 API가 요청 성공에 대한 응답으로 댓글 정보를 담은 data를 주지 않게 설계되었기 때문 (response.data)
      • 만약 서버에서 response.data안에 내가 추가한 댓글 정보 (내용, postId, commentId - 이는 서버에서 할당)을 반환한다면,
      • 이 데이터를 바탕으로 reducer에서 현재 상태를 업데이트하여
      • 서버 요청 없이도 업데이트된 댓글 목록을 즉각 즉각 반영할 수 있다.
    • 따라서 아래와 같이 설계.

  • useEffect를 통해 현재 댓글들을 불러온다.
  • 하지만 return () 부분에서, useEffect 사용 전에 currentComments를 이용해 컴포넌트들을 렌더링 하기 때문에
  • currentComments가 업데이트되지 않은 상태 (null)이라면 에러가 난다.
  • 때문에 currentComments가 있을 때에만 (null이 아닌 상태) 컴포넌트들을 렌더링 할 수 있도록
{ currentComments && ...
  • 구문을 넣어주는 것이 필요했다.
  • (나머지 액션 부분은 밑에서 설명!)

============================================================

 

3. 현재 컴포넌트가 맨 처음 마운트 (렌더링)될 때 + 특정 상태 값이 바뀔 때마다 실행

const [data, setData] = useState(false)
const [data2, setData2] = useState('default value for first render')
 
useEffect(() => {
	// if you pass some variable, than component will rerender after component mount one time and second time if this(in my case data or data2) is changed
	// if your data is object and you want to trigger this when property of object changed, clone object like this let clone = JSON.parse(JSON.stringify(data)), change it clone.prop = 2 and setData(clone).
	// if you do like this 'data.prop=2' without cloning useEffect will not be triggered, because link to data object in momory doesn't changed, even if object changed (as i understand this)
}, [data, data2] )
  • 위처럼 useEffect 두 번째 파라미터로 특정 값을 넣은 배열을 넣어준다면,
  • 맨 처음 컴포넌트가 마운트 되었을 때
  • 그리고 특정 값이 변할 때마다 useEffect가 실행된다.

 

============================================================

예시

  • 따라서 위의 내 코드에서는 addCommentDone과 removeCommentDone 값이 변할 때마다 useEffect안의 코드가 실행

============================================================

 

4. 뒷정리 할 때 

 

useEffect(() => {
	//some code
    return () -> {
    	//clean-up code
    };
  }, [data, data2] )
  • 위처럼 함수 안에 return () => {} 함수를 넣어주면
  • 뒷정리 함수로 여겨져
  • 현재 컴포넌트가 언마운트될 때 return () => {} 안 구문이 실행된다.

 

 

useEffect 사용 예제 - 크소 플젝

지금 작업 중인 토이 프로젝트의 게시판 부분 (Post View)은 이렇게 구성되어 있다.

크소 플젝 - 게시글 보기 화면

  • 전체 게시글 보기 (PostView) 컴포넌트 안에
  • 댓글 달기 (CommentForm) 컴포넌트 - 노란색 ,
  • 댓글 보기 (CommentWrapper) 컴포넌트 - 갈색 - 가 있다.

 

  • 게시글 나머지 부분 (게시글 제목, 내용, 작성자 등)은 GET /api/posts/{postId}에서,
  • 댓글 부분은 GET /api/comments/{postId}에서 받아온다.

 

  • 따라서 처음 댓글 보기 컴포넌트가 마운트되었을 때,
  • 그리고 댓글이 추가될 때마다 (addPostDone상태가 리듀서 - 사가를 통해 바뀜)
  • 또 댓글이 삭제될 때마다 (removePostDone상태가 리듀서 - 사가를 통해 바뀜!)
  • useEffect 안의 코드가 실행되어 - GET_COMMENTS_REQUEST 액션이 디스패치되어
  • 최신 댓글들을 불러오고 (currentComments),
  • currentComments를 prop으로 받아들이는 CommentWrapper 부분이
  • 리렌더링 되는 형태이다.

^_^

댓글