단일 필터링 구현
처음에는 가볍게 하나의 필터만 구현해봤다. api문서에 따르면 서울시 문화행사의 행사가 총 16개의 분류가 있어서 이것을 바탕으로 필터링을 구현했다.
일단 select 요소에 option으로 각각의 분류를 지정하고 상태변수를 하나 만들어 value, onChange 이벤트와 함께 연동했다.(나중에 배열로 만들어서 렌더링 해야할거같다.)
handleClassChage 함수에 상태 변경과 함께 분류에 맞게 fullItem을 필터링하여 배열로 만들어서 store에 있는 전역상태변수 filteredItem에 넘겨준다. 필터링하면 현재 페이지도 1페이지로 만들어준다.
const handleClassChange = (event) => {
setClassification(event.target.value);
// 해당 분류의 item만 필터링
let filteredbyClassArr = itemArr.filter(
(el) => el.CODENAME === event.target.value
);
if (event.target.value === "전체")
filteredbyClassArr = fullItem.culturalEventInfo.row;
dispatch(filteredByClass(filteredbyClassArr)); // 필터링된 배열로 상태변경
dispatch(somePage(1)); // 필터링되면 1페이지로 이동
};
그리고 나머지 코드들에서 적절히 수정하면 필터링된 item들이 화면에 렌더링된다.
여기까지는 괜찮았다....... ㅠㅠ
다중 필터링 구현
이제 다중 필터링을 구현해야 하는데 여기서 멘탈붕괴가 오기 시작했다.
문제점
분류로 한번 필터링 된 상태에서 지역으로 다시 필터링을 해야한다.
필터링 하는거 까지는 괜찮은데, 필터링이 된 상태에서 한번 더 필터링을 하면 제대로 필터링이 되지 않는 현상이 발생했다.
예를 들자면 클래식 분류에 광진구에서 하는 행사를 필터링 해서 보다가, 다른 지역인 서대문구에서하는 클래식이 보고싶어서 바로 서대문구로 필터를 바꾸면 서대문구에서 하는 클래식이 필터링 되는것이 아니라 광진구에서 하는 클래식 중에서 서대문구에서 하는 행사를 찾게 되어버려서 아무것도 출력이 되지 않는 현상이 발생했다.
2중 필터링을 하기 위해서 필터링이 된 상태의 배열에 다시 필터링을 적용시켜서 발생하는 문제였다. 그러나 다시 fullItem에서 필터링을 하게 되면 2중 필터링이 되지 않는다...
문제 해결 방안
고민을 하다가 필터의 각각의 상태를 기억하면서, 필터링을 할 때 각각의 필터상태를 모두 거치도록 로직을 짜야겠다는 생각이 들었다.
원래는 필터의 상태를 지역상태변수로 관리하기 위해 useState를 사용했는데, 바꿀 로직대로 처리를 하려면 전역 상태로 관리를 해야겠다는 생각이 들어서 각각의 필터 상태를 관리해줄 Slice를 새로 만들었다.
일단은 분류와 지역 두개 필터링만 적용하고 구현이 된다면 나머지 날짜 필터링을 추가할 계획이다.
// filterSlice.js
export const currentFilterSlice = createSlice({
name: "currentFilter",
initialState: { classification: "전체", location: "전체" },
reducers: {
setClassification: (state, action) => {
state.classification = action.payload;
},
setLocation: (state, action) => {
state.location = action.payload;
},
},
});
하나의 상태변수를 만들어 객체 형태로 분류와 지역 필터링을 넣는다. 초기값은 전체, 전체이다.
필터 section에서 각각의 선택지를 선택하면 set 으로 시작하는 reducer들이 상태변수의 프로퍼티 값을 선택된 값으로 바꾸도록 했다.
다음으로 필터링하는 함수를 작성해야 하는데, filterItem에 있는 reducer 내부에 코드를 작성하기로 했다.
export const filteredItemSlice = createSlice({
name: "filteredItem",
initialState: { filteredItem: [] },
reducers: {
filteringReducer: (state, action) => {
const { fullItem } = action.payload;
const { classification, location } = action.payload.currentFilter;
const fullItemArr = fullItem.culturalEventInfo.row;
let filteredArr = fullItemArr;
if (classification !== "전체") {
filteredArr = fullItemArr.filter(
(el) => el.CODENAME === classification
);
}
if (location !== "전체") {
filteredArr = filteredArr.filter((el) => el.GUNAME === location);
}
state.filteredItem = filteredArr;
},
},
});
이 상태변수에는 필터링된 배열을 담는다.
reducer는 전체 아이템과 위에서 작성한 currentFilter 상태를 받아서 각각의 필터링을 거친 후 배열을 반환한다.
함수는 작성이 되었으니 이제 필터 section에 적절한 로직을 구성하면 된다.
// FilterByClass.js
const currentFilter = useSelector((state) => state.currentFilter);
const { fullItem } = useSelector((state) => state.fullItem);
const dispatch = useDispatch();
const classification = currentFilter.classification;
useEffect(() => {
dispatch(filteringReducer({ fullItem, currentFilter }));
}, [classification]);
const handleClassChange = (event) => {
dispatch(setClassification(event.target.value));
dispatch(somePage(1)); // 필터링되면 1페이지로 이동
};
currentFilter와 fullItem을 전역 store에서 꺼내와서 작업을 해준다.
handleClassChange는 section을 변경하면 발생하는 이벤트 핸들러이다. 분류탭을 변경하면 해당 분류 문자열이 event.target.value로 들어와서 classification 상태변수를 바꾸고, 페이지가 1로 이동한다.
** 중요! 이벤트핸들러 마지막에 dispatch로 filteringReducer를 적용하니 바뀌기 전 필터링 상태가 전달되는 것을 확인했다. 아마도 classification 상태변수가 변경되기 이전에 dispatch가 쏴지는것이 아닐까 추측하고 있다.
그래서 useEffect hook을 사용하여 classification 상태변수가 변경될 때 filteringReducer를 dispatch 하도록 했다.
와 진짜 구현할때 기분이 짜릿했다!!
오만가지 실패를 겪으면서 굉장히 고생했는데 구현하고 나니까 별거 아니었다.. 🥲
이렇게 맞아가면서 배우는게 확실히 기억에는 남을거 같다. ㅎㅎ
'토이 프로젝트 > 서울시문화행사' 카테고리의 다른 글
Next.js 프로젝트 - 프로젝트 세팅 (0) | 2023.07.28 |
---|---|
Next.js project - 서울시 문화행사 정보 (0) | 2023.07.22 |
React로 웹페이지만들기 - 서울시 문화행사(5) (0) | 2023.03.11 |
React로 웹페이지 만들기 - 서울시 문화행사(4) (0) | 2023.03.06 |
React로 웹페이지 만들기 - 서울시 문화행사(3) (0) | 2023.03.05 |
댓글