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 27 commits into
base: main
Choose a base branch
from

Conversation

nayujin-dev
Copy link
Member

🧩 기본 과제

  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 Point

  • 첫화면 (App.jsx) : 추천방식을 선택했는지 안했는지에 따라 다른 컴포넌트를 보이게 했습니당
<Container>
        {isStarted?(
          <AfterStart
            setIsStarted={setIsStarted}
            category={category}
          />
        ):(
          <BeforeStart 
            isStarted={isStarted}
            setIsStarted={setIsStarted}
            category={category}
            setCategory={setCategory}
            setIsHome={setIsHome}
          />
        )}
      </Container>
  • 추천 방식 고르기 전 : 첫 화면에서는 category==-1이고, 추천방식을 클릭할때마다 해당 값으로 category를 바꿔서 그에 맞는 보이도록 했어용
<Description>원하는 추천 방식을 골라줘!</Description>
            <MainBox>
                {category==-1 ? (
                    categoryList.map((type,index)=>
                    <TypeofRecommand key={index} onClick={(e)=>onTypeClick(type,e)}>
                        {type}
                    </TypeofRecommand>)
                ):(
                    <TypeofRecommand selected={true}>
                        {category}
                    </TypeofRecommand>
                )}
            </MainBox>     
            <BtnBox>
                {category!==-1 &&<Btn onClick={onBtnClick}>Start!</Btn>}
            </BtnBox>
  • 추천 방식 고른 후 : 랜덤추천을 골랐으면 Random 컴포넌트를, 아니라면 NonRandom을 보이게 했어용
{category==='랜덤 추천'?(
                <Random setIsStarted={setIsStarted}/>
            ):(
                id < 3
                ? <NonRandom 
                    id={id} setId={setId} 
                    setIsStarted={setIsStarted} 
                    calculator={calculator} setCalculator={setCalculator}/>
                : <Result calculator={calculator}  setIsStarted={setIsStarted}/>
            )}
  • Design.jsx에 styled-component 모아두고 필요에 따라 import해서 사용했어용

🥺 소요 시간, 어려웠던 점

  • 9h == 평일 동안,, 두시간 이상씩 ,, 그래두 첨으로 금욜까지 심화 다했당 ㅎㅎ
  • 나름 컴포넌트를 유의미하게 분리하고 재사용하려고 노력하다보니 오래걸린거같아요!!
  • globalstyle 적용하는게에서 생각보다 버벅였어용
  • useReducer , useMemo , useCallback 을 사용하여 로직 및 성능을 최적화합니다. => 얘네 아직 완벽한 숙지는 안된것같아요..!! 어렵드앙 차이점이 확 와닿지 않아서 어렵네용,,
    • 선택지에 따른 결과 계산할 때 useMemo를 활용해봤습니당! 처음엔 useEffect에서 처리했는데, 구글링하면서 열심히 바꿔봤어요 그런데 아직 완벽히 이해되진 않았어욥..
      const calculateResult= useMemo(findResult,[calculator]);
  • 글고 제 코드 곳곳에서 Props Drilling 현상이 나타납니당 ,, 예전부터 저런 현상이 있는건 종종 겪어왔는데, 그걸 Props Drilling이라고 한다는 것을 처음알았어요ㅎㅎ 얼렁 Redux 배워서 멋드러지게 구현하고 싶어요 >.<

🌈 구현 결과물

https://www.notion.so/dosopt/3-2fc6494ca93a4fab83a4b444bbcc5e68?pvs=4

Copy link

@Yeonseo-Jo Yeonseo-Jo left a comment

Choose a reason for hiding this comment

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

가중치 부여하는 방식이 훨..씬 더 어려운 구조인것 같은데 고생이 많았넴 ㅠㅠㅠㅠ🥹
코드 꼼꼼히 짜려고 노력한게 보인다!!
그리고... 그림판으로 글씨 쓴게 너무 귀여움 이슈 !!!

pr에 써 준대로 이번 과제는 전역상태 관리를 사용할 수 없어서 props drilling이 일어나는데,
props drilling의 해결 방법이 항상 전역상태 관리는 아니라구 해!!
잘 짜여진 패턴으로 props를 내려주는게 더 좋은 방법이라고 보는 관점도 있더라구!
나도 최근에 알게 된 내용이라 슬쩍 공유하고 감니당

그럼 담주도 하이팅🖤

Comment on lines +2 to +8
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="stylesheet" href="src/index.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>

Choose a reason for hiding this comment

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

요기 lang , title 설정도 바꿔주는거 잊지 말깅!

Choose a reason for hiding this comment

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

ㅌㅌㅌㅌㅌㅋㅋㅋㅋㅋㅋㅋ 아 글씨 쓴거 귀여워.......🥹🖤

Choose a reason for hiding this comment

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

ㅋㅋㅋㅋㅋㅋㅋㅋ하/.... 귀엽다

Comment on lines +14 to +32
<ThemeProvider theme={theme}>
<GlobalStyle/>
<Header isHome={isHome} setIsStarted={setIsStarted} setIsHome={setIsHome} setCategory={setCategory}/>
<Container>
{isStarted?(
<AfterStart
setIsStarted={setIsStarted}
category={category}
/>
):(
<BeforeStart
isStarted={isStarted}
setIsStarted={setIsStarted}
category={category}
setCategory={setCategory}
setIsHome={setIsHome}
/>
)}
</Container>

Choose a reason for hiding this comment

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

수연이 리뷰에도 남겼던건데..!

나는 개인적으로 app.jsx에서는 프로젝트 전반에 필요한 설정들 (router, theme, globalStyle, 전역 적용 스타일.. 등)만 써주고 나머지는 하위 컴포넌트로 한 번 더 감싸서 모듈화 해주는편이야!
나중에 페이지랑 컴포넌트들이 더 많아지게 될 때 이렇게 해줘야 가독성이 좋고 나중에 코드 다시 볼 때도 이해하기 쉽더라고!

이 부분 한 번 고민해보고, Header, Container와 같은 컴포넌트를 MainContainer와 같이 하나의 컴포넌트로 만들어서 App.jsx에서는 MainContainer만 import 할 수 있도록 해봐도 좋을것 같아~

import { Btn, BtnBox, MainBox, TypeofRecommand,Description } from '../styles/Design';

const BeforeStart = ({isStarted,setIsStarted, category, setCategory, setIsHome}) => {
const categoryList=['취향대로 추천', '랜덤 추천'];

Choose a reason for hiding this comment

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

요건 상수데이터니까 대문자로 표기해주면 더 좋을것 같아!
CATEGORY_LIST 일케 ~

return (
<> {calculateResult &&
<>
<ResutlImg src={`/images/${calculateResult}.jpg`}/>

Choose a reason for hiding this comment

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

img에는 alt 태그 꼭 꼭 잊지 말기!

Choose a reason for hiding this comment

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

이거는 사용하는 파일인가용? global로 적용하고 싶은 스타일이라면 globalStyle에 넣어주고, 안쓰는 파일이라면 삭제합시댜!!

Choose a reason for hiding this comment

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

요거 스타일을 따로 빼 준 이유가 있을까유 ?! 궁금합니당

return ContryList[score.indexOf(Math.max(...score))];
}

const calculateResult= useMemo(findResult,[calculator]);

Choose a reason for hiding this comment

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

여기서 최적화를 시켜줬군용 굿굿

<>
<Description>{questionList[id].question}</Description>
<LevelBox>
{id+1} / 3

Choose a reason for hiding this comment

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

여기서 '3'도 상수로 바꿔주는건 어떨까용 ?!
지금은 3단계로 이루어져 있지만 나중에 단계가 추가되거나, 제거될수도 있는데 그때마다 숫자 값을 찾아서 변경하기엔 번거로울수 있습니댱
그래서 저는 TOTAL_STAGE 라는 상수를 하나 선언해놓고

Suggested change
{id+1} / 3
{id+1} / {TOTAL_STAGE}

이런식으로 활용했어요!!

사소하지만 magic number 하드코딩은 지양하는 습관을 들이는게 좋다구 생각합니당!

Copy link
Member

@SooY2 SooY2 left a comment

Choose a reason for hiding this comment

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

심화까지 진짜 수고 많아써✨✨ 컴포넌트 나누는거랑 하드코딩 안되게 신경쓴게 넘 느껴진다!!!
추천알고리즘도...👍🏻

const [loaded,isLoaded]=useState(false);

useEffect(()=>{
id>=2 ? setNextBtnContent("결과보기") : setNextBtnContent("다음으로");
Copy link
Member

Choose a reason for hiding this comment

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

이렇게 단계마다 다른 부분들 때문에 매 단계를 다른 컴포넌트로 만들었는데 이렇게 하면 한 컴포안에서 바꿀 수 있군...!!!

@@ -0,0 +1,19 @@
export const questionList=[{
Copy link
Member

Choose a reason for hiding this comment

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

이렇게 질문도 나눠서 해주니까 더 좋다!! 그리고 파일도 관련된거끼리 묶어두니까 훨씬 코드 이해하기 쉽구.. 리뷰반영할 때 나도 갈아엎어야겠어 ㅎㅎㅎㅎ

const onBackClick=()=>{
id-1>=0
? setId(id-1)
: (setIsStarted(false), setId(0))
Copy link
Member

Choose a reason for hiding this comment

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

setIsStarted(false) 해줘서 첫 단계에서 이전으로 누르면 추천방식고르는 페이지로 돌아가는건가???

<>
<Description>{questionList[id].question}</Description>
<LevelBox>
{id+1} / 3
Copy link
Member

Choose a reason for hiding this comment

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

단계 받아와서 하는 방법..!! 내거 하드코딩 잔친데 언니거엔 하드코딩이 없당👍🏻👍🏻

{id+1} / 3
</LevelBox>
<MainBox>
{loaded && questionList[id].answer.map((each, idx)=>
Copy link
Member

Choose a reason for hiding this comment

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

언니 코드 보면서 map 사용하는 느낌을 많이 익힌거같아! map사용이 안익숙해서 어떻게 써야할지 잘몰랐거덩

</MainBox>
<BtnBox>
<Btn onClick={onBackClick}>이전으로</Btn>
{temporaryAnswer[id].some((element)=> element==true)
Copy link
Member

Choose a reason for hiding this comment

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

some메서드 좋다!!

import { ResultContry, ResutlImg } from '../../styles/Design';
import { ContryList } from './ContryList';

const Calculator = ({calculator}) => {
Copy link
Member

Choose a reason for hiding this comment

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

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 진짜 추천형 알고리즘을 만들어버린 유진옹니...✨


const onRetryClick=()=>{
setIsStarted(false);
temporaryAnswer.map((eachQ,qIdx) => temporaryAnswer[qIdx]=eachQ.map(() => false));
Copy link
Member

Choose a reason for hiding this comment

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

이건 선택 초기화 시켜주는 코든건가??!!

@@ -0,0 +1,23 @@
import { css } from "styled-components";

const colors={
Copy link
Member

Choose a reason for hiding this comment

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

이렇게 쓰는거구만....

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