< 이슈 >
필터링 기능이 완성 되지 않은 상태 → 필터링 기능 개선 + 개선과정에서 발생한 문제와 이를 해결한 과정
< 요구 사항 분석 >
< AS - IS >
< TO - BE >
개선해야할 작업의 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]);
}