티스토리 뷰
Today I Learned
어제까지 큼직한 기능 구현들을 끝내고 오늘은 본격적으로 자잘한 것들을 수정하기 시작했다.
퀴즈 결과 로직
유저가 퀴즈 10문제를 풀면서 선택한 답은 컴포넌트 안에서 state로 관리하는 게 아닌 리덕스에 저장되도록 설정했다.
그래서 퀴즈 결과 페이지에서는 아래 세 가지 재료를 가지고 화면에 결과를 띄울 수 있도록 간단하게 로직을 만들었다.
1. 유저가 선택한 답
2. 퀴즈 문제 및 정답
3. 결과 출력
/* QuizResult.js */
/* 생략 */
/* 유저가 선택한 답은 리덕스에서 꺼내오기 */
const user_answer_list = useSelector((state) => state.quiz.user_answer_list)
/* 부모 컴포넌트에서 props로 넘겨 받은 퀴즈 데이터에서의 정답과 유저가 선택한 답 매치 -> 맞힌 개수 도출 */
const answerCnt = quiz_list
? quiz_list.filter((quiz, i) => {
return quiz.solution === user_answer_list[i]
}).length
: null
/* 맞힌 개수에 따라 출력할 멘트 state로 설정 */
const [resultText, setResultText] = useState({ sub: '', main: '' })
/* 퀴즈 결과 컴포넌트가 렌더링 될 때 한 번만 resultText state 설정 */
useEffect(() => {
if (answerCnt >= 0 && answerCnt < 4) {
setResultText({ sub: '아주 작은 기적...', main: '"밈기적."' })
} else if (answerCnt >= 4 && answerCnt < 8) {
setResultText({ sub: `${answerCnt}개나 맞춘 나,`, main: '제법 "밈잘알"이에요.' })
} else {
setResultText({ sub: '치료가 필요할 정도로 심각한', main: '"밈 중독"입니다.' })
}
}, [])
/* 생략 */
styled-components의 themeProvider 설정
처음에 파일은 만들어뒀는데 계속 내용 설정을 못하고 있다가
전체적인 CSS 작업에 들어가게 되면서 확정된 요소들만 세팅했다.
적용 방법은 매우 간단하다.
1. theme.js 에 세팅하고자 하는 CSS 속성들을 객체로 만든다.
2. 실행 파일에서 ThemeProvider와 theme.js를 임포트한다.
3 ThemeProvider에 theme을 props로 넘겨준 후 최상위 컴포넌트로서 나머지 하위 컴포넌트들을 감싸준다.
/* theme.js */
// 반응형 디자인을 위한 픽셀 컨버팅 함수
const pixelToRem = (size) => `${size / 16}rem`
// font size를 객체로 반환해주자.
const fontSizes = {
small: pixelToRem(9),
base: pixelToRem(12),
lg: pixelToRem(14),
xl: pixelToRem(16),
xxl: pixelToRem(18),
}
// 자주 사용하는 색을 객체로 만들자.
const colors = {
black: '#000000',
white: '#FFFFFF',
yellow: '#FFE330',
blue: '#00A0FF',
orange: '#FF8E00',
grey: '#878C92',
line: '#E5E5E5',
}
// 자주 사용하는 스타일 속성을 theme으로 만들어보자.
const common = {
flexCenter: `
display: flex;
justify-contents: center;
align-items: center;
`,
flexCenterColumn: `
display: flex;
flex-direction: column;
justify-contents: center;
align-items: center;
`,
}
// theme 객체에 감싸서 반환한다.
const theme = {
fontSizes,
colors,
common,
}
export default theme
/* App.js */
import { ThemeProvider } from 'styled-components'
import theme from './styles/theme'
function App() {
return (
<>
<ThemeProvider theme={theme}>
/* GlobalStyle을 함께 사용하는 경우 ThemeProvider의 하위에 들어가야 한다. */
<GlobalStyle />
<ConnectedRouter history={history}>
{하위 페이지 컴포넌트들}
</ConnectedRouter>
</ThemeProvider>
</>
)
}
export default App
로그인 필요/불필요 페이지 랜딩 처리
우리 조가 만드는 서비스는 컨텐츠를 소비하는 성격이 강하기 때문에
로그인을 하지 않고도 이용할 수 있는 페이지의 구분이 필요했고
url을 직접 입력하여 접근하는 경우도 고려해서 랜딩 시 어떻게 처리할지 고민하다 이전 기수의 커스텀 훅을 채용했다.
로컬 저장소에 유저 정보와 토큰이 존재하는 지에 따라 로그인 여부를 확인하고,
1) 로그아웃 상태인데 로그인이 필요한 페이지에 있는 경우 > 로그인 페이지로 이동
2) 로그인 상태인데 로그인 페이지 또는 로그인 랜딩 페이지에 있는 경우 > 메인페이지로 이동시킨다.
파라미터로는 페이지 컴포넌트 자체와 로그인이 필요한지, 불필요한지를 설정하는 불리언을 받아서
이 커스텀 훅을 실행 js 파일에 임포트한 후 아래 형태와 같이 작성해주면 된다.
/* App.js */
import Auth from './shared/auth'
function App() {
return (
<>
<ThemeProvider theme={theme}>
<GlobalStyle />
<ConnectedRouter history={history}>
<MobileFrame>
<Route path="/" exact component={Main} />
<Route path="/join" exact component={Auth(Join, false)} />
<Route path="/login" exact component={Auth(Login, false)} />
<Route path="/mypage" exact component={Auth(Mypage, true)} />
<Route path="/quiz" exact component={QuizIntro} />
<Route path="/quiz/:category" exact component={Quiz} />
<Route path="/quiz/:category/result" exact component={QuizResult} />
/* 생략 */
</MobileFrame>
</ConnectedRouter>
</ThemeProvider>
</>
)
}
export default App
로그인, 회원가입 페이지는 너무나 당연하게 로그인이 필요 없는 페이지이기 때문에 false,
마이페이지는 로그인 상태여야 접근이 가능한 페이지이기 때문에 true,
퀴즈는 로그인을 하지 않아도 접근할 수 있어야 하기 때문에 인증 커스텀 훅을 사용하지 않는다.
사실 로그인이 필요 없으면 아예 훅을 사용하지 않으면 되지만,
로그인, 회원가입 페이지는 불리언에 따라 랜딩 시 다른 페이지로 이동을 시켜줘야 하기 때문에 false로 설정하였다.
그 외에는 자잘한 css 디테일 작업을 하였다.
팀원들마다 스타일을 적용하는 방법이 제각각이라서 나중에 리팩토링할 때 꽤나 애먹을 것 같다는 생각이 들었다.
'what i learned > TIL' 카테고리의 다른 글
[TIL] 2022/01/07 Fri (0) | 2022.01.07 |
---|---|
[TIL] 2021/12/06 Thu - 레이어 팝업, 공통 alert 컴포넌트 만들기, 퀴즈 결과 로직 수정 (0) | 2022.01.06 |
[TIL] 2021/01/04 Tue - Intersection Observer API를 이용한 무한스크롤 구현, 헤더 분기 작업 (2) | 2022.01.04 |
[TIL] 2022/01/01 Sat (0) | 2022.01.01 |
2021/12/31 Fri - (0) | 2021.12.31 |