-
Notifications
You must be signed in to change notification settings - Fork 20
[유선향]-Sprint5 #56
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
[유선향]-Sprint5 #56
The head ref may contain hidden characters: "React-\uC720\uC120\uD5A5-sprint5"
Conversation
[Fix] delete merged branch github action
…-sprint1 [유선향] sprint1
이미지 파일 이름 띄어쓰기제거,이름 변경 -kdjkdjfkdjfdjk
컬러팔레트 사용을 위한 create color.css 작성
login_signup.js 파일 작성, 핸들러함수를 계획하고, 각 함수가 쓰이는 html파일에 해당 js 파일을 연결, 그리고 해당 js 파일에 필요한 함수이름을 import 했다.
로그인 페이지의 비밀번호 부분 테두리 스타일과 8글자 이상 작성 에러메시지 , 빈값일 경우 에러메시지 기능 작성 중복되는 코드가 많아서 추후 정리 필요
기존에 border red 스타일이 간혹 사라졌다가 다시 나타나는 현상 수정함.
회원가입 버튼 활성화 부분 구현, - 디렉토리 구조 정리 - 눈모양 i태그클릭시 type을 password, text로 수정하는 password_hide 함수작성, - 에러메시지가 생김에 따라 i태그가 움직이는것 수정 -앞으로의 수정 : 코드의 중보정리, 모듈화 진행예정
중복되는 코드가 많아 signup_login.js 파일을 만들어 login.html, signup.html 두파일에 적용하려 했으나, 일부 기능이 잘 구현되지 않아 일단 test.js 파일을 작성하고 코드리뷰 이후 보완후에 util.js 파일로 지정하려 함.
Resolve conflicts in README.md and package.json Merge branch 'React-유선향' of https://github.com/codeit-bootcamp-frontend/13-Sprint-Mission into React-유선향
화면 초기렌더링시 아이템 불러올수 있게 구현
베스트 아이템을 따로 리퀘스트하는 함수를 api.js에 생성, ItemsList에 따로 prop내려줌.
pageSize, bestPageSize state로 실행 디바이스에 따라서 propducts 요청 쿼리스트링 변화
베스트 아이템과 전체 아이템 영역을 스타일링 다르게하고, 반응형으로 스타일이 달라지게 구현
|
스프리트 미션 하시느라 수고 많으셨어요. |
이번에 react- select 라이브러리를 사용해봤는데, 너비가 제맘대로 잘 조정되지 않아 많이 힘들었습니다. 불러온 padding 값이 자동으로 설정되어있었는데, 모든 요소에 padding값을 지정해 보았지만 적용이 되지 않아서 참 아쉬웠습니다.아핳 select 라이브러리를 경험해보셨군요. 기능이 많이 들어가있는 라이브러리는 커스텀하기 어려울 수 있지요 😢 어느 한부분의 문제가 전혀 다른 부분에 영향을 끼치는 경우가 많아서 당혹스러웠습니다... 렌더링이 자주 일어나면 스타일드 컴포넌트에서 영향을 끼치는 경우가 생기다니...그치요 ㅠㅠ 사이드 이펙트라고도 합니다. 그럴 경우 디버깅하기 정말 힘들죠 ㅠㅠ |
| const useWindowSize = () => { | ||
| const [deviceType, setDeviceType] = useState("desktop"); | ||
| const handleResize = () => { | ||
| if (window.matchMedia("(max-width: 767px)").matches) { | ||
| setDeviceType("mobile"); | ||
| } else if (window.matchMedia("(max-width: 1199px)").matches) { | ||
| setDeviceType("tablet"); | ||
| } else { | ||
| setDeviceType("desktop"); | ||
| } | ||
| }; | ||
|
|
||
| useEffect(() => { | ||
| handleResize(); | ||
| window.addEventListener("resize", handleResize); | ||
| return () => { | ||
| window.removeEventListener("resize", handleResize); | ||
| }; | ||
| }, []); | ||
| return deviceType; | ||
| }; |
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.
감사합니다!
| const handleResize = () => { | ||
| if (window.matchMedia("(max-width: 767px)").matches) { | ||
| setDeviceType("mobile"); | ||
| } else if (window.matchMedia("(max-width: 1199px)").matches) { | ||
| setDeviceType("tablet"); | ||
| } else { | ||
| setDeviceType("desktop"); | ||
| } | ||
| }; | ||
|
|
||
| useEffect(() => { | ||
| handleResize(); | ||
| window.addEventListener("resize", handleResize); | ||
| return () => { | ||
| window.removeEventListener("resize", handleResize); | ||
| }; | ||
| }, []); |
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.
handleResize는 useEffect 내부에 선언하는게 어떨까요?
| const handleResize = () => { | |
| if (window.matchMedia("(max-width: 767px)").matches) { | |
| setDeviceType("mobile"); | |
| } else if (window.matchMedia("(max-width: 1199px)").matches) { | |
| setDeviceType("tablet"); | |
| } else { | |
| setDeviceType("desktop"); | |
| } | |
| }; | |
| useEffect(() => { | |
| handleResize(); | |
| window.addEventListener("resize", handleResize); | |
| return () => { | |
| window.removeEventListener("resize", handleResize); | |
| }; | |
| }, []); | |
| useEffect(() => { | |
| const handleResize = () => { | |
| if (window.matchMedia("(max-width: 767px)").matches) { | |
| setDeviceType("mobile"); | |
| } else if (window.matchMedia("(max-width: 1199px)").matches) { | |
| setDeviceType("tablet"); | |
| } else { | |
| setDeviceType("desktop"); | |
| } | |
| }; | |
| handleResize(); | |
| window.addEventListener("resize", handleResize); | |
| return () => { | |
| window.removeEventListener("resize", handleResize); | |
| }; | |
| }, []); |
useEffect 내부에 함수를 선언하면, 해당 함수가 useEffect의 클로저 컨텍스트 안에 들어가기 때문에, 최신 상태와 데이터를 참조할 수 있으며, 리렌더링에 의한 불필요한 리렌더링을 방지할 수 있습니다 !
또한, 서로 필요한 로직이 가까이 있어 가독성도 향상될 수 있어요 😊
| const handleResize = () => { | ||
| if (window.matchMedia("(max-width: 767px)").matches) { | ||
| setDeviceType("mobile"); | ||
| } else if (window.matchMedia("(max-width: 1199px)").matches) { | ||
| setDeviceType("tablet"); | ||
| } else { | ||
| setDeviceType("desktop"); | ||
| } | ||
| }; |
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 handleResize = () => { | |
| if (window.matchMedia("(max-width: 767px)").matches) { | |
| setDeviceType("mobile"); | |
| } else if (window.matchMedia("(max-width: 1199px)").matches) { | |
| setDeviceType("tablet"); | |
| } else { | |
| setDeviceType("desktop"); | |
| } | |
| }; | |
| const handleResize = () => { | |
| console.log("Hello !", Date.now()); // 👈👈 | |
| if (window.matchMedia("(max-width: 767px)").matches) { | |
| setDeviceType("mobile"); | |
| } else if (window.matchMedia("(max-width: 1199px)").matches) { | |
| setDeviceType("tablet"); | |
| } else { | |
| setDeviceType("desktop"); | |
| } | |
| }; |
해당 이벤트에 console.log를 호출해보면 리사이징이 될 때마다 정말정말 많은 호출하는 것을 볼 수 있을거예요 !
그만큼 성능에 좋지 못하다는 이야기겠지요?
따라서, 프론트엔드 개발자들은 이렇게 잦은 이벤트가 발생할 때(리사이징, 스크롤, 타이핑 등) 디바운싱/쓰로틀링을 통하여 최적화를 시키곤 합니다.
쓰로틀링(Throttling): 일정 시간 동안 하나의 함수만 호출되도록 하는 기법입니다. 예를 들어, 사용자가 스크롤을 할 때, 매번 이벤트를 처리하지 않고 일정 간격으로 한 번만 처리하게 합니다. 이를 통해 성능을 향상시킬 수 있습니다.
디바운싱(Debouncing): 여러 번 발생하는 이벤트 중 마지막 이벤트가 발생한 후 일정 시간이 지난 다음에 한 번만 실행되도록 하는 기법입니다. 예를 들어, 사용자가 검색어를 입력할 때, 입력이 끝난 후 일정 시간 동안 추가 입력이 없으면 검색 요청을 보냅니다.
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 Container() {
useEffect(() => {
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
}, []);
// ... Some code
}디바운싱으로 다음과 같이 최적화를 시킬 수 있습니다 !:
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
function Container() {
const handleResize = () => {
console.log('Window resized');
};
useEffect(() => {
const debouncedHandleResize = debounce(handleResize, 300);
window.addEventListener('resize', debouncedHandleResize);
return () => {
window.removeEventListener('resize', debouncedHandleResize);
};
}, []);
// ... Some code
}이렇게 하면 연속된 이벤트가 끝난 후 0.3초마다 호출하게 되어 기존보다 훨씬 최적화된 기능이 될 수 있습니다 !
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.
같은 함수를 매번 작성하기 번거롭지요. 선향님께서 하신 것처럼 이것도 훅으로 만들 수 있습니다 !
번거롭죠.. (사실 저도 위 코드는 GPT한테 맡긴 코드입니다 하하하핳ㅎ 그래서 될지는 장담못함..)
디바운싱, 쓰로틀링은 정말 흔한 기법이어서 참조할 수 있는 문서가 많습니다 !
해당 라이브러리를 사용한 코드로 볼까요?
import { useRef, useState } from 'react';
import { useDebounceCallback } from 'usehooks-ts';
function useDebounceValue(initialValue, delay, options) {
const eq = options?.equalityFn ?? ((left, right) => left === right);
const unwrappedInitialValue = typeof initialValue === 'function' ? initialValue() : initialValue;
const [debouncedValue, setDebouncedValue] = useState(unwrappedInitialValue);
const previousValueRef = useRef(unwrappedInitialValue);
const updateDebouncedValue = useDebounceCallback(setDebouncedValue, delay, options);
// Update the debounced value if the initial value changes
if (!eq(previousValueRef.current, unwrappedInitialValue)) {
updateDebouncedValue(unwrappedInitialValue);
previousValueRef.current = unwrappedInitialValue;
}
return [debouncedValue, updateDebouncedValue];
}
export default useDebounceValue;그리고 사용 방법:
import React, { useState } from 'react';
import useDebounceValue from './useDebounceValue';
const ExampleComponent = () => {
const [inputValue, setInputValue] = useState('');
const [debouncedValue] = useDebounceValue(inputValue, 500);
const handleChange = (event) => {
setInputValue(event.target.value);
};
return (
<div>
<input type="text" value={inputValue} onChange={handleChange} placeholder="Type something..." />
<p>Debounced Value: {debouncedValue}</p>
</div>
);
};
export default ExampleComponent;| }) { | ||
| const order = selectedOrder === "최신순" ? "recent" : "favorite"; | ||
| const pageSize = device === "mobile" ? 4 : device === "tablet" ? 6 : 10; | ||
| const query = `?orderBy=${order}&page=${page}&pageSize=${pageSize}`; |
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.
쿼리는 URLSearchParams로 손쉽게 사용할 수 있어요 !
(new URLSearchParams({hello: 1})).toString();
// 결과값: 'hello=1'객체로 구성할 수 있어 가독성이 좋고, URL 인코딩을 자동으로 처리하여 특수 문자나 공백이 포함된 값에서도 안전하게 동작합니다 !
URLSearchParams:
URLSearchParams인터페이스는 URL의 쿼리 문자열을 대상으로 작업할 수 있는 유틸리티 메서드를 정의합니다.
| @@ -0,0 +1,75 @@ | |||
| import Select from "react-select"; | |||
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.
말씀주신 react-select 군요 !
라이브러리를 경험하셨군요 ! 좋습니다 ! 👍
다음에는 드롭다운을 직접 만들어보는 것도 좋은 학습 경험이 될 수 있을 것 같아요. 😊
|
수고하셨습니다 선향님 ! 스프린트 미션 수행하시느라 정말 정말 수고 많으셨습니다 ! |
|
감사합니다! 이번 팀프로젝트때 다른 팀원분들 경험을 저도 많이 흡수 할수 있는 좋은기회인것 같아서 희진님을 열심히 괴롭히고 있습니다! |
감사합니다! 이번 팀프로젝트때 다른 팀원분들 경험을 저도 많이 흡수 할수 있는 좋은기회인것 같아서 희진님을 열심히 괴롭히고 있습니다!ㅋㅋㅋㅋ 열심히 괴롭혀서 많이 빼먹으세요 😊👍 |
요구사항
기본
####중고마켓
####중고마켓 반응형
심화
주요 변경사항
스크린샷
멘토에게