-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
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
[김찬기] Sprint6 #222
The head ref may contain hidden characters: "React-\uAE40\uCC2C\uAE30-sprint6"
[김찬기] Sprint6 #222
Conversation
- isFormValid 체크하는 로직 수정 (문자열인지, 파일 같은 값인지에 따라 체크하도록) - register로 보내는 onChange는 input의 onChange 전용으로 수정 - hook 에서 반환하는 onChange는 name, value를 받아서 직접 업데이트 하는 함수로 수정 - required 벨리데이션 수정 (문자열인지 체크후 검증) - rule이 없는 필드일 경우 에러가 안나도록 수정
- 숫자형태도 값을 받을 수 있도록 수정 - 보기힘든 삼항연산자 중첩 부분 리팩토링 - trigger에서 빈값이 들어가는 부분 수정
- 요청실패시 리프레시토큰이 있으면 토큰재발급후 재요청 로직 추가 - 엑세스토큰을 담아서 요청하는 통신 함수 추가 - accesstoken이 변경되면 유저정보를 가져오도록 useEffect 개선
- useAuth에서 asnycWithAuth를 가져와서 제출하는 방식으로 수정
- 에러블럭 추가 - 이미지도 필수로 넣게 조정
- user정보는 로컬스토리지에 저장안하므로 토큰을 검사 - user정보는 새로고침후 새로 가져오기전까지는 계속 null상태임
- input, textarea, tags, file에 공통적인 container 컴포넌트화 - 폼 필드 컴포넌트를 Field안에서 모아서 export
- 최근검색어가 검색인풋을 자식으로 받아서 랜더링 (검색인풋 단독으로도 사용가능하도록) - section header 스타일링 부분 수정
- asyncWithAuth 함수명 변경 (withAuth : 비동기함수를 반환만 해주는 일반 함수라는 느낌으로) - withAuth가 받는 함수실행문을 감싸도록 개선
- 검색인풋은 내부 state없이 uncontrolled로 개선 - 최근검색에서 children에게 props전달하도록 개선
- stateless하게 변경 (부모 컴포넌트에서 state 관리)
- 결과값도 state로 관리해서 사용 할 수 있도록 개선
defb4b6
to
b34e60f
Compare
function withAuth(asyncFn) { | ||
return async function (...args) { | ||
try { | ||
return await asyncFn(...args, auth.accessToken); | ||
} catch (err) { | ||
if (err.status === 401 && auth.refreshToken) { | ||
try { | ||
const newAccessToken = await handleRefreshToken(); | ||
return await asyncFn(...args, newAccessToken); | ||
} catch (refreshErr) { | ||
console.error("리프레시 요청 실패"); | ||
clear(); | ||
throw refreshErr; | ||
} | ||
} else { | ||
console.error(err); | ||
throw err; | ||
} | ||
} | ||
}; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
코드잇 강의에서 배운 wrapperFunc을 응용해보려고 했습니다.
받은 함수를 다시 돌려주는데 받은함수의 인자와 함께 토큰을 같이 넣어서 보내는 형식으로 작성했습니다.
(보충수업에서 알려주신 axios interceptor를 이용하는 방법을 다음주에 적용해보려고합니다.)
- 전달받는 인자를 간략하게 바꿈 - 전달받는 객체를 분해하여, 의존성배열에 삽입 - useList훅, 최근검색훅 개선으로 인한 전체 상품페이지 개선
- 그룹내 페이저갯수 구하는 식에서 불필요한 Math.max 삭제(항상 0보다 크게 나와서 불필함)
- App.jsx로 provider들 가져오 (index.jsx는 단순하게 두려고함) - router 정의에 루트패스 작성
- 엔터를 쳐서 태그를 입력후, blur해버리니 사용성이 안좋아서 blur를 삭제 - 한글로 태그 입력시 마지막 문자가 분리되어서 태그가 입력되는 형상을 keyup이벤트로 교체했었는데, 문제의 원인을 구글링을 통해서 알게되어 해결 (한글을 입력시 합성되고 있으면 제출안되도록)
import { useState } from "react"; | ||
import useLocalStorage from "@hooks/useLocalStorage"; | ||
|
||
const RECENT_SEARCH_SIZE = 5; | ||
|
||
export default function useRecentSearch({ initialKeyword, onChange }) { | ||
const [searchInput, setSearchInput] = useState(initialKeyword || ""); | ||
const [recentSearh, setRecentSearch] = useLocalStorage("keyword", []); | ||
|
||
// 검색창 핸들러 (submit, change, clear) | ||
function handleSearchSubmit() { | ||
if (searchInput.trim()) { | ||
setRecentSearch((prev) => | ||
[ | ||
searchInput, | ||
...prev.filter((keyword) => keyword !== searchInput), | ||
].slice(0, RECENT_SEARCH_SIZE) | ||
); | ||
} | ||
//검색인풋 초기화가 좋은 UX일까? (검색취소 버튼이 나오도록, 검색어가 떠있는게 좋은것 같음) | ||
//setSearchInput(""); | ||
onChange(searchInput); | ||
} | ||
|
||
function handleSearchChange(e) { | ||
setSearchInput(e.target.value); | ||
} | ||
|
||
function handleSearchClear() { | ||
setSearchInput(""); | ||
onChange(""); | ||
} | ||
|
||
// 최근검색 이벤트 핸들러 (click, remove, clear) | ||
function handleRecentSearchClick(value) { | ||
setRecentSearch((prev) => | ||
[value, ...prev.filter((keyword) => keyword !== value)].slice( | ||
0, | ||
RECENT_SEARCH_SIZE | ||
) | ||
); | ||
setSearchInput(value); | ||
onChange(value); | ||
} | ||
|
||
function handleRecentSearchRemove(value) { | ||
setRecentSearch((prev) => prev.filter((keyword) => keyword !== value)); | ||
} | ||
|
||
function handleRecentSearchClear() { | ||
setRecentSearch([]); | ||
} | ||
|
||
return { | ||
searchInput, | ||
recentSearh, | ||
handleSearchSubmit, | ||
handleSearchChange, | ||
handleSearchClear, | ||
handleRecentSearchClick, | ||
handleRecentSearchRemove, | ||
handleRecentSearchClear, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
최근검색과 키워드검색이 만들어내는 핸들러양이 너무 많아서, items폴더에서만 사용하는 훅으로 따로 분리했습니다...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
최근검색 추가기능까지 만들고 스프린트 미션 재미나게 하시네요~ㅋㅋㅋ
넘나 좋습니다👍
fd6c04e
to
2d24cc0
Compare
- 기존 useFilteredSearchParams 이름 변경(좀더 직관적이게) - 관리되는 params state와 url이 싱크되는 훅 - react router의 setSearchParam의 사용을 url쿼리파라미터가 이전과 비교해서 변경되었으면 작동하도록 params를 비교하도록 추가 (lodash isEqual 사용)
- number 값을 바로 쓸 수 있도록 변경
- aspect ratio를 받아서 유동적으로 쓸 수 있도록 제작 - 업로드 및 상품리스트에서 공용으로 사용가능하도록 공용 컴포넌트로 분리
- number input에 undefined가 넘어오면 경고를 해서 개선 - 기존 formatted 값 가독성좋게 변경
- 값이 없으면 formatter를 사용안하도록 설정
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
스프린트 미션 하느라 수고 많으셨어요~👏🏻
즐기고 계신게 느껴지네요😎
- 생각해보니 useFetch는 '주소'를 받아서 fetch처리하는 훅으로 사용되어야할 것 같음 (구글링의 예제 코드들을 분석해봄) | ||
- url주소 기반으로 처리하는 useFetch를 쓰게되면, 만약에 api url이 변경되거나 요청전 작업이 수정되면 수정하러 이곳저곳을 돌아다녀야 할 것 같음. | ||
- 비동기 요청함수를 받아서 처리하는 훅으로 만들어둔 useAsync를 쓰는게 더 적합해보임 | ||
- 주소를 기반으로 fetch만을 처리하는 훅으로 useFetch를 수정하고 남겨두기로 결정 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고민했던 것들 정리해서 기록하는 것 매우 좋아요~👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
개인적으로 data fetching 하는 hook 하나 (다른 api콜 할 때도 사용하는 공용 hook),
data fetching 하는 hook을 사용해서 실제 서비스에 필요한 api 콜하고 데이터를 받고 필요한 데이터 정제 및 일부 필요한 기능이 들어있는 hook 하나 이렇게 분리해서 사용하는게 깔끔했었어요.
참고 링크는 이후에 다루게 되는 react-query의 예시인데 useQuery같이 api 콜에 필요한 기능을 가진 hook이 있고, 그리고 이걸 래핑해서 구현해서 사용하는 custom hook으로 분리하는 방식으로 사용하는 방식이 좋았어요.
물론 간단한 요청의 경우 data fetching 하는 hook을 바로 사용 하는 것도 괜찮은 옵션이라 생각해요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
리액트쿼리 적용할때 참고해서 적용해보겠습니다!
- api요청 함수를 서비스쪽에 모아두고 이것을 활용해서 데이터 패칭을 하려니까 좀 복잡해진것 같습니다.
- 리액트라우터의 loader쪽에도 이 함수를 재사용하고 싶어서 분리하게 되었는데,
- 리액트쿼리 같은 라이브러리들에서도 이 서비스 함수를 이용하는 방법도 알아보려고합니당
import { useState } from "react"; | ||
import useLocalStorage from "@hooks/useLocalStorage"; | ||
|
||
const RECENT_SEARCH_SIZE = 5; | ||
|
||
export default function useRecentSearch({ initialKeyword, onChange }) { | ||
const [searchInput, setSearchInput] = useState(initialKeyword || ""); | ||
const [recentSearh, setRecentSearch] = useLocalStorage("keyword", []); | ||
|
||
// 검색창 핸들러 (submit, change, clear) | ||
function handleSearchSubmit() { | ||
if (searchInput.trim()) { | ||
setRecentSearch((prev) => | ||
[ | ||
searchInput, | ||
...prev.filter((keyword) => keyword !== searchInput), | ||
].slice(0, RECENT_SEARCH_SIZE) | ||
); | ||
} | ||
//검색인풋 초기화가 좋은 UX일까? (검색취소 버튼이 나오도록, 검색어가 떠있는게 좋은것 같음) | ||
//setSearchInput(""); | ||
onChange(searchInput); | ||
} | ||
|
||
function handleSearchChange(e) { | ||
setSearchInput(e.target.value); | ||
} | ||
|
||
function handleSearchClear() { | ||
setSearchInput(""); | ||
onChange(""); | ||
} | ||
|
||
// 최근검색 이벤트 핸들러 (click, remove, clear) | ||
function handleRecentSearchClick(value) { | ||
setRecentSearch((prev) => | ||
[value, ...prev.filter((keyword) => keyword !== value)].slice( | ||
0, | ||
RECENT_SEARCH_SIZE | ||
) | ||
); | ||
setSearchInput(value); | ||
onChange(value); | ||
} | ||
|
||
function handleRecentSearchRemove(value) { | ||
setRecentSearch((prev) => prev.filter((keyword) => keyword !== value)); | ||
} | ||
|
||
function handleRecentSearchClear() { | ||
setRecentSearch([]); | ||
} | ||
|
||
return { | ||
searchInput, | ||
recentSearh, | ||
handleSearchSubmit, | ||
handleSearchChange, | ||
handleSearchClear, | ||
handleRecentSearchClick, | ||
handleRecentSearchRemove, | ||
handleRecentSearchClear, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
최근검색 추가기능까지 만들고 스프린트 미션 재미나게 하시네요~ㅋㅋㅋ
넘나 좋습니다👍
].slice(0, RECENT_SEARCH_SIZE) | ||
); | ||
} | ||
//검색인풋 초기화가 좋은 UX일까? (검색취소 버튼이 나오도록, 검색어가 떠있는게 좋은것 같음) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
function setValue(value) { | ||
try { | ||
//useState의 setState에 callback을 넘기는 행동처럼 사용가능하도록 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
const valid = value.length && !error; | ||
|
||
function handleKeyDown(e) { | ||
if (e.nativeEvent.isComposing) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
요구사항
기본
상품 등록
심화
상품 등록
주요 변경사항
프로젝트 셋팅
변경사항
스크린샷
멘토에게
access token이 필요한 요청일 경우에, 모든 통신실패에 대해서 재발급된 token으로 재요청하는 프로세스가 필요한걸까요?