Skip to content
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

[ 3주차 기본/심화/생각 과제 ] 점메추 과제 #6

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Rose-my
Copy link
Member

@Rose-my Rose-my commented Nov 10, 2023

🌱 기본 조건

  • 기본조건1

✅ 선택 과정은 총 3단계입니다. ( 3개 → 3개 → 2개)

✅ 아이템은 총 18개 이상입니다. (3 x 3 x 2 = 18)

위는 “최소”기준이며 그 이상의 개수는 가능합니다.

  • 기본조건2

✅ 전역상태관리 라이브러리, context 사용 금지 ❌

✅ Router 사용 금지 ❌


🧩 기본 과제

  1. 추천 종류 선택
    • 취향대로 추천 / 랜덤 추천 중 선택합니다.
    • 선택시 다음화면으로 넘어갑니다.

[취향대로 추천]

  1. 답변 선택

    • 호버시 스타일 변화가 있습니다.
    • 클릭시(선택시) 스타일 변화가 있습니다.
  2. 이전으로, 다음으로(결과보기) 버튼

    • 아무것도 선택되지 않았을 시 버튼을 비활성화 시킵니다.

      → 눌러도 아무 동작 X

      → 비활성화일 때 스타일을 다르게 처리합니다.

    • 이전으로 버튼을 누르면 이전 단계로 이동합니다.

    • 다음으로 / 결과보기 버튼을 누르면 다음 단계로 이동합니다.

    • 버튼 호버시 스타일 변화가 있습니다.

  3. 결과

    • 선택한 정보들에 맞는 결과를 보여줍니다.

[ 랜덤 추천 ]

  1. 숫자 카운트 다운
    • 3 → 2 → 1 숫자 카운트 다운 후 결과를 보여줍니다.
    • 추천 결과는 반드시 랜덤으로 지정합니다.

[ 공통 ]

  1. 결과 화면
    • 다시하기 버튼

      → 랜덤추천이면 랜덤 추천 start 화면으로, 취향대로 추천이면 취향대로 추천 start 화면으로 돌아갑니다.

      → 모든 선택 기록은 리셋됩니다.


🌠 심화 과제

  1. theme + Globalstyle 적용

    • 전역으로 스타일을 사용할 수 있도록 적용해보세요
  2. 애니메이션

    • 랜덤 추천 - 카운트다운에 효과를 넣어서 더 다채롭게 만들어주세요!
  3. 헤더

    • 처음으로 버튼

      → 추천 종류 선택 화면일시 해당 버튼이 보이지 않습니다.

      → 처음 추천 종류 선택 화면으로 돌아갑니다.

      → 모든 선택 기록은 리셋됩니다.

[ 취향대로 추천 ]

  1. 단계 노출

    • 3단계의 진행 단계를 보여줍니다.
  2. 이전으로 버튼

    • 이전으로 돌아가도 선택했던 항목이 선택되어 있습니다.
  • 6. useReducer , useMemo , useCallback 을 사용하여 로직 및 성능을 최적화합니다.

생각과제

  • 리액트에 대하여
  • 컴포넌트는 어떤 기준과 방법으로 분리하는 것이 좋을까?
  • 좋은 상태 관리란 무엇일까?
  • 렌더링을 효과적으로 관리하는 방법은 무엇이 있을까?
  • Props Drilling이란 무엇이고 이를 어떻게 해결할 수 있는가?

🍎 PR

  1. App.jsx
    • UseState
      • 각 페이지의 선택 결과 저장해서 마지막 페이지에 가져오기
      • key값으로 Component 핸들링
    • Component : 각 페이지 저장
      • ChoosePage
      • ChooseFavor
      • FavorDetails
      • DishDetails
      • SoupDetails
      • ShowFavor
      • ChooseRandom
      • ShowRandom
  2. data
    • IMG_DATA
      • export default IMG_DATA
      • import IMAGE_DATA from "../data/imgData";
  3. styles
    • GlobalStyles
    • themeProvider
  4. countdown
    • UseEffect
      • 각 페이지의 선택 결과 저장해서 마지막 페이지에 가져오기
  const [time, setTime] = useState(3);
  const [image, setImage] = useState(null);
  const [imageName, setImageName] = useState("");

  useEffect(() => {
    if (time > 0) {
      setTimeout(() => setTime(time - 1), 1000);
    } else {
      const imageNum = Math.floor(Math.random() * IMAGE_DATA.length);
      setImage(IMAGE_DATA[imageNum].src);
      setImageName(IMAGE_DATA[imageNum].name);
    }
  }, [time]);
  1. keyframes
    • 타이머 애니메이션 삽입
const TimerAnimation = keyframes`
  0% {
    transform: scale(10);
    opacity: 1;
    color: white;
  }

  100% {
    transform: scale(10);
    opacity: 1;
    color: #db6060; 
  }
`;
  1. themeprovider
    • import styled, { ThemeProvider} from "styled-components";
      • 공통된 태그의 style은 theme에서 가져오기
const common ={
  Container:`
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;

    width: 100vw;
  `,
  ButtonContainer:`
    display: flex;
    justify-content: center;
    align-items: center;

    flex-wrap: wrap;

    gap: 1rem;
    padding: 0;
  `
}
const theme ={
  common,
};

export default theme;
const Container = styled.main`
  ${({ theme }) => theme.common.Container};
  background-color : ${({ theme }) => theme.colors.favYellow};
`;

🥺 소요 시간, 어려웠던 점

  • 4일 하루에 4-5시간
  • 개념부터 정리하느라 시작이 늦었지만 왕초보스터디하면서 스스로 블로그에 작성해보니까 어느정도 감이 생긴것 같아요 -❌ 생각해보니까 아닌 것 같아요.
  • 저는 마지막 페이지에서 그 전 페이지들의 모든 props를 받아와서 연산을 통해 사진을 보여주는 코드로 구현해봤는데 이 방법말고 이전 페이지와 다음 페이지가 서로 연관이 되어있게 props를 받아오게 구현하고 싶었어요. 그런데 도저히 그렇게는 구현이 안됐습니다.
  • 각 페이지 컴포넌트에서 props 불러오기/전달하기가 헷갈렸어요
{favorKey===4 &&<SoupDetailsPage ForthButtonKey={ForthButtonKey} YesSoup={YesSoup}} 
  • App.jsx에서 SoupDetailsPage 컴포넌트에 ForthButtonKey와 YesSoup를 넘겨주고 ->
const SoupDetailsPage = ({ForthButtonKey, YesSoup}) => {
  • SoupDetailPage.jsx는 const 안에서는 YesSoup()로 표시해서 함수를 실행할 수 있고 함수에서는(onClick)은 {ForthButtonKey}로 받아옵니다
  • 둘 다 함수형으로 App.jsx에서 선언했어요
  const ForthButtonKey=()=>{
    setFavorKey(favorKey+1);
  }
  const [soup, setSoup]=useState(10);
  const YesSoup=()=>{
    setSoup(0);
  }
  const handleYesSoup =()=>{
    setSoup(0);
    YesSoup();
    setIsSoupSelected(true);
  }
<ForthButton disabled={!isSoupSelected} onClick={ForthButtonKey} isSoupSelected={isSoupSelected}>

🍏 구현 결과물

🌈 취향대로 추천과 다시하기로 선택을 다르게 할 시 보여주기

default.mov

🌈 랜덤 추천과 다시하기

default.mov

🌈 다음으로 버튼 disable -> 선택 시 able로

disable.mov

🌈 이전으로 다음으로 구현

default.mov

🌈 선택 다르게 해서 결과에 맞게 보여주기

default.mov

Copy link

@imeureka imeureka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

미뇽 넘넘 수고많았어!! 코드리뷰열심히 해볼게 ❤️❤️

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

하하 나도 이거 항상 까먹어 나도 이거 리팩토링 해야돼 킄킄.."KO..."
시작 할 때마다 노트북에 붙여놔야겠어.

${({ theme }) => theme.common.Container};
background-color : ${({ theme }) => theme.colors.favYellow};
`;
const DetailsContainer = styled.div`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main처럼 시맨틱 태그도 활용해주자! article로 바꾸면 될 것 같아!

<DetailsContainer>
<h2>랜덤추천</h2>
<ButtonContainer>
<StartButton type="button" onClick={RandomDetails}>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

나는 공통으로 사용되는 버튼들은 컴포넌트 말고 공통?ui로 뺐어 그러면 코드의 재사용성을 높일 수 있을 거 같아서 고민 해봤는데 미뇽도 한번 트라이해봐!!!

export default ChooseRandomPage;

const Container = styled.main`
${({ theme }) => theme.common.Container};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

옹 theme 적용시켜봐야겠다 나도!! 대단해 미뇽

</NoodleDishButton>
<MeatFishDishButton type="button" onClick={handleMeatFishDish} dish={dish}>
<p>고기or해물</p>
</MeatFishDishButton>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

각 버튼의 스타일이 중복되는 것을 방지하려면 버튼에 재사용 가능한 스타일 구성 요소로 구현해보는 것도 괜찮을 것 같아 예를 들어 DishButton style을 만들어서!😊

<h2>오늘은 어떤 종류가 먹고 싶어?</h2>

<ButtonContainer>
<KrFavorButton type="button" onClick={handleKrFavor} favor={favor}>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또 버튼들 같은 경우 나는 const categoriesLevel1 = ["소년", "청년", "중년"]; 해서 map함수로 돌렸는데 이러면 코드가 짧아지고, 모든 경우에 대해서 재사용이 가능해지니까 참고해도 좋을 것 같소!!👍

colors,
common,
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

theme까지 넘 잘했다 고생많았어 미뇽!!!!

const MeatFishDish=()=>{
setDish(2);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

나는 이제 컴포넌트를 분리해서 거기에 쓰이는 변수들을 정리했는데 미뇽이도 예를 들어, 랜덤 컴포넌트를 만들어서 거기에 이제 변수들도 넣어서 관리하면 더 가독성 좋은 + 재사용성에 용이한 코드가 될 것 같아1
app.jsx에 이렇게 함수와 변수선언한 것은 가독성을 좀 해치는 것 같아!폴더구조를 설계해서 거기에 맞는 함수를 정리해 보는 것도 좋을 것 같아🙌🙌

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

가영이의 추천대로 전역으로 쓰는 것보다 해당 변수들이 쓰이는 컴포넌트 내에서 만들어주면 더 깔끔해질 것 같아요ㅎㅎ 값 추적이나 변수 관리에도 더 용이할 것 같고요!

Copy link

@urjimyu urjimyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

과제하면서 고민한 흔적이 곳곳에 보여서 너무 좋았어요! 너무너무 고생 많았습니다🥺 리뷰하면서 저랑 다르게 구현한 부분들 보면서 많이 배웠습니다👍🏻❣️

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 gitignore에 추가해줘도 될 것 같아요~!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리액트 프로젝트 만들면 자동으로 생기는 이런 애들 중에 필요없는 것들은 삭제해주면 좋아요☺️


return (
<>
<GlobalStyle/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ThemeProvider 사용법
이 글 참고해서 ThemeProvider에 theme을 넣어주고 그 밑에 GlobalStyle을 넣어주면 좋을 것 같아요:)
다만 저 링크와는 다르게 우리는 theme 파일을 이미 따로 만들어줬으니까 그걸 불러와서 ThemeProvider에 넣어주면 됩니다!

const MeatFishDish=()=>{
setDish(2);
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

가영이의 추천대로 전역으로 쓰는 것보다 해당 변수들이 쓰이는 컴포넌트 내에서 만들어주면 더 깔끔해질 것 같아요ㅎㅎ 값 추적이나 변수 관리에도 더 용이할 것 같고요!

const ChooseFavorPage = ({ FavorDetails }) => {
return (
<>
<ThemeProvider theme={theme}>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 App.jsx 를 피드백대로 고친 후에 지워주면 됩니다~!

}


const common ={
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 이렇게 css까지 theme으로 빼주었군요! 저도 재사용하는 스타일링이 있으면 이렇게 해봐야겠어요👍🏻

if (time > 0) {
setTimeout(() => setTime(time - 1), 1000);
} else {
const imageNum = 6*selectedFavor + 2*selectedDish + 1*selectedSoup;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

계산한 점수값에 해당하는 인덱스 사진을 띄워주는 형식으로 결과를 보여주게 되면 나중에 데이터 항목이 추가되거나 삭제되었을 때 결과가 달라질 수 있을 것 같아요..! 배열 형식으로 선택한 카테고리를 state로 저장해서 일치하는 설명을 가진 사진을 보여주는 방식으로 수정할 수 있을 것 같아요오
ex) ["국물 있음", "한식"]

pink : "rgb(255, 192, 203)",
black: "#000000"
}
const pixelToRem = (size) => `${size / 16}rem`;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와 rem 변환까지 꼼꼼하게 고민한 게 보여서 너무 좋아요! 저도 추가하겠습니다ㅎㅎ

</ButtonContainer>

<ButtonContainer>
<BackButton type="button" onClick={BackButtonKey}>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 계속 여러 번 재사용되는 버튼 같은 컴포넌트들은 아예 따로 만들어준다음 import해서 사용하는 방법도 있습니다!
아래 글은 그냥 참고용! 저희 과제에서는 꼭 저렇게 padding 값까지 넘겨줄 필요 없이 모양이 완전히 똑같은 버튼들을 재사용하기 위해서 차이가 생기는 부분만(text같은 부분) props로 넘겨서 컴포넌트로 빼주면 좋을 것 같아요
[React] React로 범용적인 재사용 컴포넌트 만들어보기
출처:
https://junjangsee.tistory.com/entry/React로-범용적인-재사용-컴포넌트-만들어보기 [개발 여행:티스토리]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants