두번째 과제의 요구사항은 대략적으로 이러하였습니다.
초기 셋팅은 첫번째 과제물과 유사하게 진행하였습니다.
불필요한 파일이 제거된 CRA를 생성하고,
ESLint,Prettier,husky가 설정이 된 Repo를 main이 올린 뒤, 팀원들이 모두 클론하여 각자의 브런치를 만들고 진행하였습니다.
추가적으로 이번 과제물에서는 자체적으로 코딩 컨벤션을 정하고 진행해보자는 의견이 있어 컨벤션을 추가해보았습니다. 지정한 컨벤션은 아래와 같습니다.
여기에 더해
과제물 제출 구현 시간이 어찌보면 매우 짧은 편이였습니다.
토요일 2시 30분쯤에 시작하여, 월요일 12시이전 제출, 자는 시간을 제외하면 결과적으로 일요일 자정까지는 완성이 되어야 하는, 하루 반나절정도의 시간이 주어졌습니다.
이런 상황에서 저희 팀은 우선적으로, 각자가 기능을 구현 한 후. git Repo의 Discusions을 제출 전날 자정 9시까지,
각자의 요구사항에 맞는 기능구현 방법을 적어두고, 어느분의 방법이 좋다고 생각하는지 각자가 comments를 달아 의견을 표시하기로 하였습니다.
이러한 방법을 통해 중요 로직만을 코드리뷰 할 수 있도록 하고, BestPractice의 선정을 조금 더 효율적이게 할 수 있도록 하엿습니다.
선정은 코드리뷰를 통해 누구의 코드가 가장 이상적인지를 투표를 통해 선정하였습니다.
사실 이방법은 엄연하게는 BestPractice를 뽑는 방법이라 생각치는 않습니다. 왜냐하면 어느분의 코드에서 A라는 부분이 좋았고, 다른분 코드에서는 B라는 코드가 좋았는데. 이 두 부분을 적절히 잘 조정하여 코드를 만들어내는것이 BestPractice에 가까운 방법이라고 생각하였습니다.
하지만 각자의 코드 스타일과 구현방법이 다르며, 이 부분을 조정하여 리팩토링 하는데는 추가적인 시간이 들어갑니다. 또한 이러한 방식으로 같은 방식의 코드를 구현한다면 그것은 협업이 되고, 원티드 과제물의 기본적인 원칙인 개인 과제물과는 어울리지 않는다 생각하였습니다.
하지만 그럼에도, 좋은 점의 일부라도 가져와서 리팩토링을 적은 시간이나마 시간을 할당하여 하는것이 맞다 생각하였습니다.
기본적인 진행방식은 아래와 같았습니다.
토의 진행 -> 진행 결과 Discusions을 공지 -> 기능구현 -> 토의 진행...
의 반복이였습니다.
이전 과제와는 달리 Discusions을 적극적으로 활용하였습니다.
Discusions을 토의 결과를 정리하는것과, 자신의 기능구현을 설명하는것.
이렇게 두가지 용도로 사용하였습니다.
토의 에는 는 구현 방법에 대한 논의, 코드 구조 및 기타 개발 정보공유 등이 이루어졌습니다.
개인적인 구현 과정에서 막혔던 부분의 List는 아래와 같았습니다.
이부분은 loading과 error를 어떻게 같이 구현해야할지 고민을 좀 하다, 이전에 공부하였던 velopert 개발자님의 깃북을 참고하여 거의 대부분 따라하였습니다.
하지만, 기존 state값을 저장하는 부분은 적혀있지 않았기때문에, 약간의 코드를 변형하여 사용하였습니다.
// 리듀서 부분
if (list) {
return {
...state,
[key]: asyncState.listSuccess(state[key], action.payload),
};
}
// 사용되는 state
listSuccess: (state, payload) => {
return {
loading: false,
data: state.data ? state.data.concat(payload) : payload,
error: null,
};
},
인피니티 스크롤의 구현방법 또한, 팀원이 공유해주신 방법을 따라 했습니다.
공유된 페이지에서는 useRef,useEffect,Interaction Observer를 사용한 구현이 적혀있었는데.
약간 미완성인채로 적혀있었습니다. useRef값을 useEffect에서 의존성 배열에 넣어줘야 하는데, 이것을 넣어주지 않아 초기에 값이 undefined가 표시되어 정상적인 실행이 되지 않았습니다.
때문에, useRef 대신 useState값을 useRef와 유사하게 사용하였습니다.
useEffect(() => {
const option = {
threshold: 0,
};
const observer = new IntersectionObserver(onHandleObserver, option);
if (target) {
observer.observe(target);
}
return () => {
observer && observer.disconnect();
};
}, [target, onHandleObserver]);
하지만 이 방법은 페이지가 리렌더링 될때마다 state 값 또한 재할당되고, 쓸데없이 리렌더링 되는 방법으로서 좋은 방법이 아니라고 생각합니다.
결과적으로, useRef의 값을 useEffect의 의존성 배열에 넣으면 해결되는 문제였습니다.
List를 구현하며 느낀점은, 첫 렌더링시 useEffect 함수가 두번 실행된다는것입니다. 이 부분에 대해 왜 그런지 검색해보니 CRA로 생성된 리액트 프로젝트에서는
React.StrictMode가 기본적으로 적용이 되어있는데, 이것은 오류를 잘 찾아내기 위해 기본적으로 2번의 렌더링을 거치게 되고, 이로인해 useEffect가 두번 실행되었습니다.
index.js에 있는 <React.StrictMode> 태그를 제거 하였습니다.
gitHub의 글은 대부분 마크다운으로 이루어집니다. 그래서 정보를 가져올때 컨텐츠 값이 마크다운일 경우가 많은데. 이것을 CSS로 변환을 어떻게 해야하는지에 대한 문제가 있었습니다.
찾아낸 해결법
최종적인 코드
마크다운 문법 변환
const markdown = marked(body);
// tailwind의 typo 기능을 구현하기 위하여 <article className="prose> 적용
<article className="prose prose-stone sm:w-[578px] w-screen">
{<div dangerouslySetInnerHTML={{ __html: markdown }}></div>}
</article>
해당 로직을 통해 css처리화된 마크다운 컨텐츠
많은 분들의 과제물 결과를 보면, 컴포넌트를 작은 단위로 세분화 해서 만들었다고 느꼈습니다.
하지만 제 방식의 경우, 컴포넌트화는 정말 큰 레이아웃으로서 재활용되는 부분만 컴포넌트화를 진행하였습니다. 그 편이 개발 방식도 편하고, 컴포넌트를 너무 세분화 하면 보기 불편하지 않을까 하는 생각이였습니다.
사실 이부분은 아직도 애매모호한 부분이라고 생각되고 있습니다. 더욱 공부하고 노력해야 될 부분이라고 생각합니다.
그래도 이번 과제에서 적용된 부분은 일부있습니다.
tailwind CSS를 사용하는경우 큰 설정없이 반응형이 이루어진다고 생각하고 있었습니다. flex와 w-screen 등을 사용하면 자동적으로 반응형이 이루어지니까요.
하지만 약간의 착각이였습니다.
min-w 같은 옵션도 그냥 적당히 580px정도 주면 되겠지 하고 PC화면으로만 테스트 해봤는데, 모바일 환경에서는 깨져보이고, 실제 핸드폰으로 접속햇을경우는 더욱 안좋게 보이는 구나 라는 경험을 하였습니다.
때문에 반응형을 사용하는경우, 뷰 포트와 퍼센트 css를 사용할때 min-w 값과 기본 w값을 주는것에 대해서 신중하게 접근해야 한다는걸 알았습니다.
구현방법
(작업 기한 1.5일)
http://wanted-pre-onboarding-june.s3-website.ap-northeast-2.amazonaws.com/
https://github.com/jun-05/wanted_assignment_02
Discusions을 통하여 의견을 나누고, 최종적으로 선정된 분의 과제물을 최종 과제물로 제출하였습니다. 이분의 코드에서 좋다고 생각하였던 부분은 아래와 같습니다.
사실 저는 막히는 부분은 검색하여 대부분 약간만 변형하여 구현하였는데, 이런식으로 변형하여 코딩을 구현하는점은 많이 배워야 한다고 생각했습니다.
선정 결과 링크(비공개)
코딩 부분
팀 진행 부분
개인 과제 기준입니다.