useEffect 의존성 배열 활용하여 비동기 처리

Darlene·2022년 6월 26일
0

TIL

목록 보기
9/10
post-thumbnail
  • useEffect에 대해서 다시 생각해보기
  • useEffect에서 의존성배열의 역할
  • setState는 동기적일까 비동기적일까
  • useEffect에서 여러 상태를 변경해야하는경우 이를 동기적으로 처리하는 방법

< 이슈 >

필터링 기능이 완성 되지 않은 상태 → 필터링 기능 개선 + 개선과정에서 발생한 문제와 이를 해결한 과정

< 요구 사항 분석 >

  • 필터링 조건이 설정되면 페이지는 항상 1페이지여야 한다.
  • 필터링 조건 및 페이지가 변경된 상태에서 특정 상품 페이지로 이동한 다음 뒤로가기 버튼을 눌렀을 때 이전 필터링 상태가 보존되어야 한다.

< AS - IS >

  1. 전체 카테고리 목록이 포함되어있는 api를 호출한다.
  2. 필터를 적용한 경우 검색 API를 호출해서 필터링된 상품 리스트를 조회한다.
  3. 상품을 선택해서 상품 상세페이지로 진입한다.
  4. 뒤로가기 버튼을 클릭하면 모든 필터는 초기화되고 전체카테고리와 1페이지로 이동한다.

< TO - BE >

  1. 전체 카테고리 목록이 포함되어 있는 API를 호출한다.
  2. 필터를 적용한 경우 검색 API를 호출하면서 router query를 이용해서 선택한 필터정보를 url에 저장한다.
  3. 상품을 선택해서 상품 상세페이지로 진입한다.
  4. 뒤로가기 버튼을 클릭하면 이전에 저장된 필터 정보에 해당하는 페이지로 이동한다.

개선해야할 작업의 2번과정에서 setState가 동기적으로 처리되지 않고 비동기적으로 한번에 묶어서 batch update한다는 사실을 알게되었습니다.

따라서 useEffect 훅에서 의존성 배열을 활용해서 비동기작업에 대한 순서를 제어할 수 있도록 처리했습니다.

const Product = () => {
  
  const [categories, setCategories] = useState([]);
  const [filter, setFilter] = useState({});
  const [selectedCategory, setSelectedCategory] = useState({});

  useEffect(() => {
    const fetch = async() => {
       //1. 카테고리 목록을 조회한다.
			 await getCategories();
       //2. 필터를 적용하고 상품상세를 조회하고 뒤로가기를 한 경우
       if(router.isFilter) {
         //기존에 사용했던 필터를 그대로 다시 적용한다.
         setFilter({
            orderBy : router.query.orderBy,
						search : router.query.serach,
						category : router.query.category
         });
         //카테고리 선택 ui에서 선택한 카테고리를 설정시키기 위해 
         //selectedCategory를 기존에 선택한 값으로 변경
         setSelectedCategory(categories.filter(c => c.id === router.query.category)[0]);
         //3. 필터가 적용된 상품을 조회힌다.
				 await getProducts();
			 }
    }
    fetch();
  },[]);

}

위의 코드를 예시로 설명하면, 2번과정에서 문제가 발생했습니다. 카테고리를 조회하고 조회해온 카테고리를 categories라는 state에 업데이트 해주고 기존에 선택했던 카테고리 선택 ui를 변경시켜주기 위해서 selectedCategory값을 기존에 저장한 값으로 변경시켜주는 코드입니다.

selectedCategory에 기존에 필터에서 설정한 카테고리값을 변경시켜주었지만 ui상에서 재랜더링을 하면서 카테고리가 변경되지 않는 문제가 있었습니다.

원인은, 1번과정에서 카테고리 목록을 조회하고 setCategories를 실행할때 setState가 동기적으로 처리되는것이 아니라 핸들러 내부에서는 모든 상태값 변경을 한번에 모아서 batch update해주기 때문에 selectedCategory를 변경해주는 시점에는 전체카테고리가 존재하지 않기때문에 저장했던 카테고리 id에 해당하는 카테고리 정보를 찾는것이 불가능했습니다.

이를 해결하기 위해서는 useEffect내부에서 카테고리를 항상 먼저 조회하고 categories라는 state에 상태값이 업데이트되고나서 필터관련 상태변경이 일어나야했습니다. 즉, 비동기적인 작업에대한 순서를 제어해야했습니다.

이를 위해서는 useEffect훅에서 사용하는 의존성 배열을 이용하면 처리할 수 있습니다.

즉, 카테고리가 조회되고나서 나머지 로직을 실행해야하므로 카테고리는 항상 조회해야하므로 의존성배열을 설정하지 않고 카테고리가 조회되고나서 실행되야 하는 로직은 의존성 배열로 카테고리를 설정하면 이 둘의 순서를 제어할 수 있습니다.

const Product = () => {
  
  const [categories, setCategories] = useState([]);
  const [filter, setFilter] = useState({});
  const [selectedCategory, setSelectedCategory] = useState({});

  //의존성 배열을 설정하지 않았기때문에 컴포넌트 랜더링 과정에서 항상 처음으로 실행되는 useEffect
  useEffect(()=> {
			//1. 카테고리 목록을 조회한다.
			getCategories();
  },[]);

  //의존성배열로 categories를 설정했으므로 categories가 변경된 경우에 해당 useEffect훅이 실행
  useEffect(() => {
	     //2. 필터를 적용하고 상품상세를 조회하고 뒤로가기를 한 경우
       if(router.isFilter) {
         //기존에 사용했던 필터를 그대로 다시 적용한다.
         setFilter({
            orderBy : router.query.orderBy,
						search : router.query.serach,
						category : router.query.category
         });
         //카테고리 선택 ui에서 선택한 카테고리를 설정시키기 위해 
         //selectedCategory를 기존에 선택한 값으로 변경
         setSelectedCategory(categories.filter(c => c.id === router.query.category)[0]);
         //3. 필터가 적용된 상품을 조회힌다.
				 await getProducts();
			 }
  },[categories]);

}

0개의 댓글