기술 로그 - Dumboz/yalp GitHub Wiki
- [문제 상황] git repository 의 수정 권한을 팀원에게 부여한 상황(kanban board 수정을 위해)에서 push 만을 막아야 함
- [해결 방법] 팀원 로컬 repository 내에서
git remote set-url --push <REMOTE_NAME> no_push
- [문제 상황] 잘못된 PR이 온 경우 이를 revert 해야 함
- [해결 방법]
git revert --no-commit HEAD~<NUM>..
에 현재 최신 Commit 이력에서 되돌아갈 commit 개수를 입력하면 HEAD가 이동함
- [문제 상황] 되돌리려는 commit 중 merge commit이 포함된 경우
- [해결 방법]
(가정: 최신 commit이 merge commit 인 상황)
step 1) git log를 확인하여 현재 commit hash를 확인한다
step 2) 현재 merge commit에서 merge 된 commit 을 확인한다
commit 8f937c683929b08379097828c8a04350b9b8e183
Merge: `8989ee0` `7c6b236`
Author: Ben James <[email protected]>
Date: Wed Aug 17 22:49:41 2011 +0100
Merge branch 'gh-pages'
Conflicts:
README
현재 merge에서는
8989ee0
(1번)와7c6b236
2번) 두 commit이 merge 되었음
step 3) git revert <현재 Hash> -m <되돌아갈 hash의 번호>
ex) git revert 8f937c68 -m 1 (1번 commit으로 되돌아감)
BrowserRouter : history 를 관리할 수 있게 만들어 주는 react router Oulet : swap children NavLink : 함수로 인수를 전달하면 isActive 인자가 전달되어 선택 여부를 반환한다 useNavigate :
[문제 상황] yelp API 에서 client side로 request 요청을 하는데 필요한 CORS header를 제공하지 않는다. (참고 1)
- 'cors-anywhere.herokuapp.com' 을 get 요청 시 url 앞에 붙여주면, API에 우회하여 요청 가능하다. 하지만, 1일 요청 제한이 있어 근본적인 방법이 될 수 없다
- 따라서 server로 Yelp API 요청을 해야 하는 상황이므로, client 에서 api 요청을 했을 때 server가 요청하는 것처럼 동작하기 위해 proxy 중계 서버를 두었다
- 중계 서버 설정 방법 : client package.json 에 "proxy" 프로퍼티에 back server url을 작성한다.
- server를 만들지 않고도 package.json에 proxy를 yelp api url로 설정하면, 자체적으로 proxy 서버가 구동되어 origin을 바꿔 api요청을 우회할 수 있을줄 알았다.
- [답변] package.json에 proxy는 origin을 바꾸는 역할이 아니고, 중계 서버가 무엇인지 지정하는 설정이다.
- [답변] proxy 서버는 중계 서버인데, yelp api 주소를 중계 서버로 설정한 것이 문제였다. (yelp api가 중계 서버가 될 수 없는 이유: yelp는 중계 서버가 아니라, 목적지가 되어야 한다. 중계 서버로 설정할 이유가 없다.) 따라서 중계(proxy)서버를 직접 구축하여, 해당 서버에서 API 요청을 보내도록 우회 및 설정하였다.
- 왜 클라이언트에서 보낸 요청은 CORS에러가 나고, proxy 서버로 우회했을 때는 CORS에러가 나지 않는가?
- CORS에러는 브라우저가 발생시키는 것이다.
- 브라우저는 SOP 정책에 의해 origin이 다르면 통신을 할 수 없지만 CORS 예외를 두면 통신이 가능하다.
- CORS 예외 처리 방식은 응답 header 내 'Access-Control-Allow-Origin' 속성이 포함되어 있어야 한다. 이 속성이 없거나, 해당 속성 값에 클라이언트 origin이 포함되어 있지 않으면 CORS 에러가 발생한다.
- 따라서 중계 서버를 두면, 통신할 수 있는 이유는 다음 2가지이다.
- 중계 서버와 API 서버간 통신은 origin이 달라도 통신을 할 수 있다.
- 중계 서버와 브라우저 간 통신은 중계 서버의 응답 header 내 'Access-Control-Allow-Origin' 속성이 와일드카드(*)로 설정되어 있어, CORS 에러가 발생하지 않는다.
- dispatch에 비동기처리를 담당하는 action을 전달할 경우 일어나는 일에 대해 조금 더 정리가 필요하다.
7. Warning: Cannot update a component (searchForm) while rendering a different component (searchPage) ...
- [문제 상황] filter Section의 click event handler를 useCallback 함수로 설정하였음. 이 때 dependency array를 빈 배열로 설정할 경우, useLocation으로 불러온 search(query)가 변경 될 경우 해당 search 를 반영하지 않아 filter 적용 시 에러 발생
- [해결 방법] 이벤트 핸들러 내에 자신이 의존하는 search 를 dependency array에 추가함
const handleClick = useCallback(
e => {
...
const query = QueryString.parse(`search`.replace(/^\?/, ''));
...
[`search`, setSearchParams],
);
- [문제 상황]
React.lazy
,React.Suspense
를 사용하여 코드 스플릿팅을 진행하던 도중 아래와 같은 에러가 발생함.
Error: The above error occurred in one of React components
-
[이슈 분석] lazy하게 불러올 컴포넌트 파일들을
default
로 내보내지 않았기 때문에 발생한 문제였다. -
참고 페이지: CRA- Code splitting
- 문제 코드
async function call(query, setState) {
const { data } = await axios.get('/api' + query);
setState(data);
return { data };
}
const Exam = () => {
const [state, setState] = useState({});
const { pathname, search } = useLocation();
call(pathname + search, setState);
return <div>{JSON.stringify(state)}</div>;
};
-
[문제 상황] Exam 컴포넌트 안에서 setState를 비동기 요청을 수행하는 Call 함수에게 넘겨주어 state를 변경하도록 하였더니, 계속해서 리렌더링이 발생함.
-
[원인 파악] 컴포넌트 안에서 비동기 함수를 호출해 state를 변경하면, 다시 컴포넌트를 렌더링 하며 비동기함수를 호출되어 state가 변경되고, state가 바뀌었기 때문에 다시 컴포넌트를 렌더링하는 무한 루피가 발생한다.
-
[해결 방안]
- react-async라이브러리에서 제공하는
useAsync()
hooks을 사용 -
useEffect()
를 사용해서 Mount시에만 비동기 함수를 호출하도록 구현
- 이 방법은 state가 초기 값일 때, 비동기 함수가 state를 update해줬을 때, 즉 2번 렌더링이 발생함.
- [문제 상황] cannot read properties of undefined (reading 'displayName') 이라는 에러가 발생함
- [해결책]
export default
로 꺼내온 컴포넌트를일반 export 방식
으로 내보낸 컴포넌트를 가져오는 방식을 사용해서 발생한 에러였음. default 로 내보낸 컴포넌트를 가져오는 방식을 사용하여 해결함.
- [문제 상황] 전체 컴포넌트에게 styled-component로 작성된 GlobalStyle 컴포넌트를 적용해주어야했음.
- [해결책] Global decorators 를 사용하여 해결함. storybook - decorators
- 상태 관리를 하면서 중복을 최소화 시키는 방법
-
[문제 상황] Price filter button을 만들 때, 여러 개의 버튼을 한 번에 상태관리를 하게 되면서 이슈가 됨. 하나의 컴포넌트 안에 다양한 상태가 존재하고 이를 useState로 관리하다 보니 코드의 중복으로 가독성이 떨어짐.
-
[해결책] useReducer을 사용해 하나의 reducer라는 함수로 관리해주면서 응집도를 높이고 가독성 이슈도 해결함.
-
[이유] useState와 useReducer 둘 다 고려를 해보았지만 응집도, 가독성, 확장성 측면에서 useReducer가 훨씬 장점이 많다고 판단.
- StoryBook
-
[문제 상황]
Buttons must have discernible text
에러가 남. aria-label이 없어서 접근성 준수를 하지 못함. -
[해결책] aria-label, aria-labelledby로 접근성 준수시켜 모든 test 통과됨.
button
은 반드시 role이 필요.
useEffect(() => {
const loader = new Loader({
apiKey: process.env.REACT_APP_MAP_API_KEY,
version: 'weekly',
});
loader.load().then(setMap(...));
}, [businesses, GEOArr]);
-
문제 상황 리렌더링할 때 의존할 필요 없는 값을 의존하여 set과 동시에 리렌더링되고 리렌더링 되며 set이 다시 실행되며 무한 루프에 빠짐
-
해결 방안 의존해야 할 값을 정리하여 의존 배열을 제대로 세팅함
useEffect(() => {
...
}, [businesses]);
- 중첩된 컴포넌트의 click 이벤트가 중복 문제
-
[문제 상황] 상위 컴포넌트에 click 이벤트를 등록한 이후, 하위 컴포넌트를 click 할 경우 하위 컴포넌트의 이벤트가 상위와 하위 컴포넌트 모두 중복으로 발생하는 문제
-
[해결 방법] pointer-event(CSS 속성으로 그래픽 요소가 어떤 상황에서 포인터 이벤트의 대상이 될 수 있는지 지정함)를 none으로 설정하면 해당 컴포넌트는 포인터 대상이 될 수 없기 때문에 이벤트 클릭이 발생할 수 없음 (다만 해당 css 속성을 가진 컴포넌트의 하위 컴포넌트에서 다른 pointer-event를 설정할 경우 포인터 대상이 될 수 있음)
- 컴포넌트 내 여러 상태 관리
- [문제 상황] 부모 컴포넌트 내부에 자식 컴포넌트 별로 useState를 통해 상태를 관리할 경우 코드의 중복이 발생하여 코드 가독성이 떨어짐. 또 이럴 경우, 코드의 응집도가 떨어지는 문제가 발생할 수 있고, 향후 관리해야 하는 상태가 증가할 경우 중복된 코드를 작성해야 함.
- [해결 방법] 각 컴포넌트의 초기 상태를 배열에 저장하고, useReducer를 활용해 상태 관리 로직을 일원화하여 코드의 중복을 방지하고 응집도를 높임
- 리스트 렌더링 시, key 값을 컴포넌트에 prop으로 전달할 경우
- [문제 상황] 리스트 렌더링 시, 상위 컴포넌트 내 하위 컴포넌트에
key
프로퍼티 이름으로 프로토타입을 전달할 경우 해당 컴포넌트에 전달되는 값은 undefined가 됨 - [해결 방법] 단순히
key
라는 이름을 제외한 다른 이름으로 프로퍼티를 전달하면 해결 됨
-
mouseOver 대신 CSS Hover 사용하여 모달 구성
-
keyPress 대시 keyDown
- arrow key event 의 경우 keyPress 대신 keyDown을 사용할 경우 인식 됨
- List rendering 시, 랜더링 되는 각 컴포넌트 참조
-
[문제 상황] 키보드 트랩을 구현하기 위해서, 배열을 통해 랜더링된 컴포넌트별로 useRef를 통해 해당 컴포넌트를 참조하려고 하였으나 ref가 항상 마지막 컴포넌트 참조값만 가지게 됨
문제 코드
const selectionRef = new Array(length).fill(useRef(null))
-
[해결 방법] useRef를 여러 개 만드는 것이 아니라, useRef의 초기값을 배열로 선언하여 ref의 current를 업데이트 시켜 줌
- useCallback 사용 시, dependency array 설정의 중요성
- [문제 상황] filter Section의 click event handler를 useCallback 함수로 설정하였음. 이 때 dependency array를 빈 배열로 설정할 경우, useLocation으로 불러온 search(query)가 변경 될 경우 해당 search 를 반영하지 않아 filter 적용 시 에러 발생
- [해결 방법] 이벤트 핸들러 내에 자신이 의존하는 search 를 dependency array에 추가함
const handleClick = useCallback(
e => {
...
const query = QueryString.parse(`search`.replace(/^\?/, ''));
...
[`search`, setSearchParams],
);