We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
공공데이터 API에서 받은 하루 동안의 특정 경로의 고속버스 운행 리스트 데이터를 전역 상태인 useTowardBusListStore()에 Array concat으로 기존 배열 데이터 + 받은 데이터를 저장하고 있었다.
zustand로 전역 store를 만들었으며, 아래에서 concat 코드만 보면 된다.
import { create } from 'zustand'; import type { ForwardBusListState } from './index.types'; const initialState = { forwardBusList: [], }; const useForwardBusListStore = create<ForwardBusListState>((set) => ({ ...initialState, reset: () => set({ ...initialState }), concat: (newforwardBusList) => set((state) => ({ ...state, forwardBusList: [...state.forwardBusList, ...newforwardBusList], })), deleteByStartId: (targetStartId) => set((state) => ({ ...state, forwardBusList: state.forwardBusList.filter( (forwardBus) => forwardBus.startId !== targetStartId ), })), })); export default useForwardBusListStore;
아래 코드는 페이지가 처음 렌더링 될 때, 공공데이터 API에서 받아온 정보를 useForwardBusListStore ()의 concat()을 호출해서 전역 상태에 넣고 있다.
useEffect(() => { getBusTicketsAPI( searchQuery.startId || 'NAEK032', searchQuery.destId || 'NAEK300', convertYYYYMMDD(searchQuery.startDate) ) .then((data) => { concat( convertBusTicketsToBusList(data.response.body.items.item, searchQuery) ); }) }, []);
Q0. 이 때 어떤 문제가 발생할까?
Q1. 어떻게 side effect를 없앨 수 있을까?
Q2. 그렇다면 이게 왜 side effect로 간주되는 걸까?
Q3. side effect를 없앴을 때 성능 이슈는 없을까?
이 부분들에 대해 [실력 좋은 친구](https://github.com/algoORgoal)와 이야기하면서 더 깊게 이해할 수 있었다.
A1. 먼저 어떻게 side effect를 없앨 수 있을지 이야기해보았다. 물론 StrictMode를 주석처리한다는 선택지는 제외하고서 말이다.
A1-1. 처음 떠오르는 생각은 원래 있던 배열 내용 뒤에 concat으로 이어붙이는 것이 아니라, 원래 있던 배열을 제거하고 대신 새로운 배열을 넣는 방법이었다.
A1-2. 이 문제를 해결하기 위해선 기존 상태를 탐색하고 필터링해서 존재하지 않는 것만 추가하면 된다.
A2. 그런데 왜 배열을 단순히 concat 하는 것이 side effect를 발생시키는지 의문이 들었다. 지금 사례에서는 그다지 부작용이 일어나 보이지 않아서 뭔가뭔가 다른 사례를 생각해 보기로 했다.
사례1) 만약 API를 호출하는데 응답이 지연되어 재호출을 시도했으나 지연된 응답과 재호출 응답이 두 번 도달하여 각각 전역 상태를 변경한 경우
사례2) 전역 상태 store 변경 함수가 여러 컴포넌트에서 호출될 가능성이 있고, 동시에 호출되어 전역 상태를 변경한 경우
위 두 사례 모두 다 중복 필터링 검증을 하지 않으면 전역 상태에 중복 값이 저장되게 된다!!!
A2-1. 게다가 순수 함수의 정의가 동일 입력에 대한 동일 출력이므로 애초에 단순 concat을 해서 반환하는 함수는 순수 함수가 아니었던 것이다!!!!
concat을 해서 반환하면 동일한 배열 입력을 계속 반복해서 주었을 때 return 값은 계속 달라지게 된다.
A3. 그런데 중복 필터링 검증을 하면 안 할 때에 비해 탐색을 다 돌려야해서 성능 이슈가 생길 것 같았다.
원래 길이 n의 배열이 있고, 새로 추가될 배열이 m이라 하면 단순하게만 봐도 O(nm)의 시간이 걸린다.
성능 이슈는 어떻게 해결 가능할까 배열이 아니라 객체로 저장하거나 id 기반 정규화가 필요하다. hashing을 해놓는 것도 좋을 수 있다.
id 기반 정규화를 프론트에서 진행해도 되지만 배열을 객체로 바꾸는 시간이 너무 길다면 백에서 정규화된 데이터를 받아오는 게 나을 수 있을 것이다.
그런데 state는 상태 불변성을 위해 항상 새로운 객체를 만든다.
이 때문에 immutable.js 등으로 시간복잡도를 줄여야 할 수 있다.
The text was updated successfully, but these errors were encountered:
#56
Sorry, something went wrong.
다만, useShallow는 만능이 아니다. 어차피 object안의 property끼리는 얕은 비교를 하기 때문에, object내에서 사용하지 않는 property가 있다면 depth를 하나 더 파고들어서 property를 가져와야 불필요한 리렌더링을 막을 수 있다.
나쁜 예시
const { a, b } = useStore(state => useShallow({ a: state.a, b: state.b })); const { property1 } = a; // 실제로는 a 내부의 property1만 사용
a 내부에 property2가 있을 경우, property2가 변경될 때마다 불필요한 리렌더링 발생한다.
좋은 예시
const { property1, b } = useStore(state => useShallow({ property1: state.a.property1, b: state.b }));
코드에서 직접적으로 사용되는 property1, b가 바귈 때마다 렌더링되므로 불필요한 렌더링을 막을 수 있다.
algoORgoal
Turtle-Hwan
Successfully merging a pull request may close this issue.
문제 상황
공공데이터 API에서 받은 하루 동안의 특정 경로의 고속버스 운행 리스트 데이터를 전역 상태인 useTowardBusListStore()에 Array concat으로 기존 배열 데이터 + 받은 데이터를 저장하고 있었다.
zustand로 전역 store를 만들었으며, 아래에서 concat 코드만 보면 된다.
아래 코드는 페이지가 처음 렌더링 될 때, 공공데이터 API에서 받아온 정보를 useForwardBusListStore ()의 concat()을 호출해서 전역 상태에 넣고 있다.
의문 사항 및 문제 정의
Q0. 이 때 어떤 문제가 발생할까?
Q1. 어떻게 side effect를 없앨 수 있을까?
Q2. 그렇다면 이게 왜 side effect로 간주되는 걸까?
Q3. side effect를 없앴을 때 성능 이슈는 없을까?
이 부분들에 대해 [실력 좋은 친구](https://github.com/algoORgoal)와 이야기하면서 더 깊게 이해할 수 있었다.
해결 방안
A1. 먼저 어떻게 side effect를 없앨 수 있을지 이야기해보았다. 물론 StrictMode를 주석처리한다는 선택지는 제외하고서 말이다.
A1-1. 처음 떠오르는 생각은 원래 있던 배열 내용 뒤에 concat으로 이어붙이는 것이 아니라, 원래 있던 배열을 제거하고 대신 새로운 배열을 넣는 방법이었다.
A1-2. 이 문제를 해결하기 위해선 기존 상태를 탐색하고 필터링해서 존재하지 않는 것만 추가하면 된다.
A2. 그런데 왜 배열을 단순히 concat 하는 것이 side effect를 발생시키는지 의문이 들었다. 지금 사례에서는 그다지 부작용이 일어나 보이지 않아서 뭔가뭔가 다른 사례를 생각해 보기로 했다.
사례1) 만약 API를 호출하는데 응답이 지연되어 재호출을 시도했으나 지연된 응답과 재호출 응답이 두 번 도달하여 각각 전역 상태를 변경한 경우
사례2) 전역 상태 store 변경 함수가 여러 컴포넌트에서 호출될 가능성이 있고, 동시에 호출되어 전역 상태를 변경한 경우
위 두 사례 모두 다 중복 필터링 검증을 하지 않으면 전역 상태에 중복 값이 저장되게 된다!!!
A2-1. 게다가 순수 함수의 정의가 동일 입력에 대한 동일 출력이므로 애초에 단순 concat을 해서 반환하는 함수는 순수 함수가 아니었던 것이다!!!!
concat을 해서 반환하면 동일한 배열 입력을 계속 반복해서 주었을 때 return 값은 계속 달라지게 된다.
A3. 그런데 중복 필터링 검증을 하면 안 할 때에 비해 탐색을 다 돌려야해서 성능 이슈가 생길 것 같았다.
원래 길이 n의 배열이 있고, 새로 추가될 배열이 m이라 하면 단순하게만 봐도 O(nm)의 시간이 걸린다.
성능 이슈는 어떻게 해결 가능할까
배열이 아니라 객체로 저장하거나 id 기반 정규화가 필요하다. hashing을 해놓는 것도 좋을 수 있다.
id 기반 정규화를 프론트에서 진행해도 되지만 배열을 객체로 바꾸는 시간이 너무 길다면 백에서 정규화된 데이터를 받아오는 게 나을 수 있을 것이다.
그런데 state는 상태 불변성을 위해 항상 새로운 객체를 만든다.
이 때문에 immutable.js 등으로 시간복잡도를 줄여야 할 수 있다.
The text was updated successfully, but these errors were encountered: