생각기록
2023-01-19 / 개발자 MBTI 조사 / React Redux 본문
선생님 사이트
이걸 통해 무엇을 배우나요!?
• 리액트 SPA(Single Page Application) 제작
• Styled-Components 활용
- 글로벌 스타일 적용
- 컴포넌트 디자인
• Redux 활용
기초 세팅
Npx create-react-app mbti-app
필요 모듈을 한큐에 설치
npm i redux react-redux @reduxjs/toolkit styled-components
폴더 구조 세팅
• Redux 활용을 위한 폴더 구조를 만들어 봅시다!
Redux 기초 셋팅
- src 폴더 최상위 index.js 파일 세팅
- Vscode 의 추천 대로 createStore 가 아닌 configureStore 사용!
- rootReducer 임포트
- Provider 임포트 후, App 감싸주기 + store 부여
- Redux 개발자 도구 사용을 위한 코드 추가!
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './store';
// 스토어 만들기
const store = configureStore({ reducer: rootReducer });
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);
reportWebVitals();
rootReducer 설정
Src/store/index.js 에서 선언된 리듀서를 임포트 하고 있으므로 해당 파일 로 이동!
사실상 SPA(Single Page App) 이기 때문에 combineReducers 를 활용 할 필요가 없지만, 나중을 위해 연습
추후 모듈 추가시 이런 구조가 있으면 편합니다.
새로운 spa 가 추가될 경우 보통 리덕스 모듈이 추가되고, 해당 spa는 라우팅으로 구현을 한다.
*spa 싱글 페이지 어플리케이션
mbti store 설정
• 실제적으로 일을 하게 될, mbti store 를 설정해 봅시다!
• 초기 State 를 설정
• DB 연동을 하지 않을 것이므로 필요 데이터 설정!
• 액션 타입 설정
• 액션 함수 설정
• 리듀서 만들기
초기 상태 설정
• MBTI 질문 목록
• 현재 페이지 값
• Mbti 전체 결과 값
• 전체 결과에 대한 설명 값
• 추가 이미지 주소 값
페이지에 따라 보여지는 결과물이 달라지도록 할 것임
survey 즉, 질문 항목에 배열로 키와 값을 가진 객체들 정보를 넣엇다.
키와 값
question :
answer
Action Type 설정
• 지금 App 에서 필요한 Action Type 은 어떤 것들이 있을까요?
• 먼저 페이지를 다음 장으로 넘기는 기능!
• 전달 값? → 필요 X
• 선택에 따른 결과를 반영하는 기능!
• 전달 값? → 선택에 따른 결과 값 전달 필요
• 마지막 페이지에서 결과를 리셋하는 기능!
• 전달 값? → 필요 X
Action 생성 함수 설정
• 외부에서 Store 내부 함수의 구조는 알 필요는 없습니다!
• 외부에서 원하는 Action 에 따른 기능을 Dispatch 를 통해 전달할 Action 함수를 설정해 봅시다!
• 지금 있는 Action Type 은 CHECK / NEXT / RESET 이므로 각각 Type 에 맞는 함수를 설정해 봅시다!
payload 값을 reducer에게 전달!
Reducer 만들기
• 이제 실제적으로 State 변경 관리하는 Reducer 를 만들어 봅시다!
• Dispatch 에 의해 전달 받은 action 의 type 값에 따라 원하는 기능을 수행 하는 역할을 하면 됩니다
• Reducer 가 해당 파일의 export default 가 됩니다!
• Type 구분은 보통 Switch 를 통해 사용 합니다
• 코드 가독성이 if 문 대비 좋고, Default 가 강제 되는 부분!
CHECK
E 선택하게 되면 빈문자열에 + E 더해주고
S를 선택하면, S를 붙여주면 된다!
(문자열을 뒤에다가 하나씩 더하는 기능을 만들어 주면 된다.)
...state , 변화해줄 값
NEXT
state.page // ( 0 )
+ 1
RESET
그리고 설정한 것들을 합친다!
스토어 index.js 리덕스 통합관리 설정
컴포넌트 제작 기초 작업!
App.js 코드 정리
• React 기본 코드를 정리해 봅시다!
• 하는 김에 public 폴더의 index.html 의 주석도 정리 합시다!
이 파일은 레고의 기초판이라고 생각한다
그림요소를 직접 넣지 않고
컴포넌트를 끼워 맞추는 역할을 한다
이미지를 퍼블릭 폴더에 폴더만들어서 넣기
시작 페이지 제작(Start.jsx)
• 페이지가 로딩 되면 제일 처음 보이는 Start 페이지를 제작해 봅시다!
• 글자와 이미지, 버튼의 조합으로 간단하게 만들어 봅시다!
• 버튼은 페이지 리로딩을 막기 위해 <a>태그로 구현!
• Styled 컴포넌트를 사용하여 꾸미기! • 컴포넌트와 분리 하기 위해 pages 폴더를 만들고 만들기!
Styled-components 꾸미기!
• Styled-components 를 사용해서 꾸며 봅시다!
• 각각의 태그를 별도로 이름을 변경하고, 해당 컴포넌트를 변수로 받은 다음 Styled-components 를 사용하여 디자인!
Start 페이지 삽입 + 메인 틀 잡기
작성한 Start 페이지를 Main 컴포넌트에 삽입
전체 컴포넌트를 담을 컨테이너 역할을 하는 Main 컴포넌트의 스타일도 잡 아 줍시다!
src > app.js
Button 컴포넌트 제작
• Button 컴포넌트는 테스트 시작, MBTI 선택지 선택, 다시 하기 등등 다양한 곳에서 재사용이 될 예정입니다!
• React 의 특수화 개념을 사용해서 기초 스타일인 Button 컴포넌트를 제작 하고 해당 컴포넌트를 이용하여 각각의 색과 기능을 가진 버튼으로 만들어 사용해 봅시다!
• Button 컴포넌트는 props로 부터 받아와야 할 값이 버튼의 텍스트, 이벤트 핸들러, 메인 색상, 서브 색상, Hover 시 색상의 값을 받아와야 합니다!
• MyButton 이라고 명명한 이후, Styled-components 로 꾸미기
• Styled-components 는 현재 컴포넌트에서 전달한 props 를 받아서 처리 가 가능하므로 편리하게 랜더링 시점에 디자인이 결정 되는 다이나믹 디자인 이 가능
프롭스에 따라 같은 버튼 컴포넌트로 색을 다른 버튼 구현 가능
메인 서버 호버 컬러는
스타일드 컴포넌트에서 받기위해 쓰는 것
SASS 와 & 사용해서 스스로 지칭하기
css 는 중첩이 안됨
SASS는 중첩이 가능해서
자식요소들도 쓸 수 있다.
import React from 'react';
import styled from 'styled-components';
export default function Button({
text,
clickEvent,
mainColor,
subColor,
hoverColor,
}) {
const MyButton = styled.a`
position: relative;
display: inline-block;
cursor: pointer;
vertical-align: middle;
text-decoration: none;
line-height: 1.6em;
font-size: 1.2em;
padding: 1.25em 2em;
background-color: ${(props) => props.mainColor};
border: 2px solid ${(props) => props.subColor};
border-radius: 0.75em;
user-select: none;
transition: transform 0.15s ease-out;
transform-style: preserve-3d;
margin-top: 1em;
&::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
right: 0;
left: 0;
right: 0;
background: ${(props) => props.subColor};
border-radius: inherit;
box-shadow: 0 0 0 2px ${(props) => props.subColor};
transform: translate3d(0, 0.75em, -1em);
}
&:hover {
background: ${(props) => props.hoverColor};
transform: translateY(0.25em);
}
`;
return (
<MyButton
onClick={clickEvent}
mainColor={mainColor}
subColor={subColor}
hoverColor={hoverColor}
>
{text}
</MyButton>
);
}
OrangeButton 으로 특수화
• 기본이 되는 Button 컴포넌트를 만들었으므로 특수화를 사용하여 OrangeButton 컴포넌트를 제작해 봅시다!
• 원하는 텍스트와 색상 값을 props 로 전달하고, 이벤트 핸들러는 사용 시점 에서 결정이 될 것이므로
그대로 전달만 합시다!
버튼컴포넌트 가져온다음에 값을 고정한다.
텍스트나 이벤트는 불러온 얘가 지정하기 때문에 PROPS로 받는다.
메인 서브 호버는 고정으로 지정한다. ( 색이 지정된 컴포넌트를 만드는 것)
app.js
가져다 적용해보자.
나온다!
Styled-coponents GlobalStyle
글로벌 스타일 적용!
• 리액트는 다양한 컴포넌트의 조합으로 사용이 됩니다!
• 그래서 보통 컴포넌트 단위로 디자인이 적용이 되죠
페이지 전체에 대한 폰트 또는 기본 스타일이 필요하다면 어떻게 하 면 될까요?
SPA 인 경우는 App.css 에 글로벌 스타일을 적용하면 되고
MPA 인 경우에는 전체를 감싸는 최종 컴포넌트에 스타일을 적용 해도 됩니다!
다만, Styled-components 의 경우는 이러한 방식보다 자체 기능을 통해 전체 페이지에 글로벌 스타일을 적용합니다
GlobalStyle 컴포넌트 제작
• Components 폴더에 GlobalStyle.js 파일을 만들고 GlobalStyle 컴포넌 트를 제작해 봅시다!
• Styled-components 는 createGlobalStyle 이라는 메소드를 제공하여 글로벌 스타일 적용을 가능하게 합니다!
• 필요한 것들을 설정해 봅시다!
일단 글로벌스타일 컴포넌트를 만들자
APP.JS에서 최상단에 글로벌 스타일 올려두면 끝!
오.. 신기해
페이지 분기 처리
• 지금 만드는 App 은 페이지에 따라서 보여줘야 하는 부분이 다릅니다!
• Page 가 0 이면 → Start 페이지 보여주기
• Page 가 설문의 길이와 같이 같을 때 까지→ 설문 조사 페이지 보여주기
• Page 가 설문의 길이를 넘어가면 → 결과 페이지 보여주기
Page 의 상태에 따라서 각각의 페이지를 렌더링 하는 방식으로 분기 처리를 해봅시다!
• 리액트의 경우 라우팅 보다는 조건부 렌더링 또는 3항 연산자, if 문으로 처 리 해주는 방법이 더 편리합니다
여기서부터 리덕스 활용
유즈셀렉터
페이지 0 스타터 페이지
0이 아니면 설문조사
설문의 길이를 넘어가면, 결과페이지를 보이도록 표현해보겟습니다
조건부랜더링과 삼항연산자를 써서 하면 라우팅 처리 필요없을것
state.mbti.page..
Mbti 페이지 제작
• 이제 설문을 하는 Mbti 페이지를 제작해 봅시다!
• 기존의 Button 컴포넌트를 활용해서 설문을 선택하는 SkyblueButton 컴포넌트를 작성하고 활용!
• Page 의 번호를 가져와서 해당 번호에 맞는 설문의 text 값을 SkyblueButton 에 담아서 출력 하기!
SkyblueButton 특수화
• 기존 OrangeButton 을 활용하여 색상 값만 변경하여 Skyblue 버튼 만들기!
페이지 제작
시간 관계상 프로그래스바는 피피티 보고 만드세요
이벤트 핸들러에 액션 생성 함수 지정
액션 생성 함수 지정
• 이제 페이지를 넘기는 기능을 하는 액션 생성 함수인 next() 를 dispatch 를 이용하여 Reducer 에 전달해 봅시다!
• Start 컴포넌트의 테스트 시작이라는 버튼에 지정! • Mbti 컴포넌트의 선택지 선택 버튼에 지정!
스타트 페이지 변경 해주고,
Mbti 페이지도 이 기능을 달아버리자
디스패치가 편지가방 들고 리듀서에게 간다!
값을 추가하고...
결과를 보여줘야함
Progress Bar 만들기
• 현 진행 상황을 보여주는 Progress Bar 도 만들어 봅시다!
• Progress.js 컴포넌트 작성하기
• Progress Bar 의 값은 현재 Page / 전체 설문 배열의 길이 값으로 표시하 면 됩니다!
• Progress Bar 의 바깥 부분을 먼저 그리고, 자식 요소가 부모의 크기를 상 속 한 다음 색을 입혀서 % 로 구현
import React from 'react';
import styled from 'styled-components';
export default function Progress({ page, maxPage }) {
return (
<MyProgress>
<div>
{page} / {maxPage}
</div>
<Fill>
<Gauge percent={(page / maxPage) * 100}></Gauge>
</Fill>
</MyProgress>
);
}
const MyProgress = styled.div`
margin-top: 3em;
`;
const Fill = styled.div`
width: 100%;
height: 10px;
background-color: #777;
margin-top: 1em;
text-align: left;
`;
const Gauge = styled.div`
background-color: skyblue;
display: inline-block;
height: inherit;
position: relative;
top: -4px;
width: ${(props) => props.percent}%;
`;
Progress Bar 삽입
• 만들어진 ProgressBar 를 삽입해 줍시다
• Props 로 전달할 값은, 현재 page 값과 전체 설문의 수 이므로 해당 정보도 props 로 전달해 주면 됩니다
결과를 만드는 Check() 삽입!
Check() 액션 생성 함수 삽입!
• 이제 페이지는 잘 넘어 갑니다!
• 그럼 MBTI 조사 결과 값을 만들어야 겠죠!?
• 해당 기능은 CHECK Action 이 담당합니다!
Check() 액션 생성 함수
Check() 액션 생성 함수는 결과 값 만을 전달 받네요?
리듀서에서의 동작
액션 생성 함수로 전달 받은 결과를 mbtiResult 라는 결과 문자열에 추가를 해주는 액션이 끝!
=> check() 함수를 호출 할 때, 설문 객체에 포함 된 결과 문자열만 절달
Dispatch 로 Check() 전달!
동작 확인
결과 출력 페이지 작성
PinkButton 특수화
• 기존 OrangeButton 을 활용하여 색상 값만 변경하여 PinkButton 만들 기!
이제 redux 에 모인 결과를 출력
• MBTI 결과가 잘 반영 되는 것을 확인 하였으니, 해당 결과를 보여줄 결과 페 이지인 Show.jsx 를 만들어 봅시다!
• Show 페이지는 Mbti 최종 결과가 들어있는 mbtiResult 값과, Mbti 결과 값에 맞는 설명 + 이미지를 출력해 주면 됩니다!
• 먼저 텍스트 부터 입력해서 디자인 부터 하고 결과 값 출력을 해봅시다
이제 리덕스에서 값 받아와!
Redux 에서 결과 값 출력하기!
• 페이지 디자인은 마쳤으니 이제 Redux 에서 결과 값을 받아서 출력해 봅시 다!
• MBTI 결과는 Store 의 mbtiResult 에 있으므로 해당 값을 받아오기
• 그리고 설명은 각각의 MBTI 결과 값을 Key 로 가지는 객체로 선언을 하였기 때문에 편리하게 접근이 가능합니다!
이해해보기
1. mbti.mbtiResult는 check() 액션 생성 함수 실행시 문자열이 추가된다
완성된 4글자를 result에 넣는다.
2. mbti.explaination. 키 > 가 그 문자열임
filter 함수 처리 필요없이 이렇게 했다.
Reset() 액션 생성 함수 전달
다시하기 버튼 기능 추가!
• 이제 다시하기 버튼을 눌렀을 때, 페이지가 최초로 돌아가는 기능을 추가해 주면 됩니다!
• 이미 RESET 기능(page 를 0 으로 만들고,mbtiResult 를 초기화)은 구현 이 되었으니 dispatch 를 통해 전달만 합시다
App.js 분기 처리
• 이제 결과 페이지도 보여줘야 하기 때문에, 결과 페이지에 대한 분기 처리도 해봅시다!
• Page 가 0 → Start 컴포넌트
• Page 가 1 ~ n → Mbti 컴포넌트
• Page 가 n + 1 → Show 컴포넌트
• If 문을 쓰는 것 보다는 간단하게 3항 연산자를 2중으로 써서 처리 해봅시다
페이지가 0 이면 스타트 페이지
page !== survey.length(4) + 1 ? > 즉 네번의 질문 후 + 1은 결과페이지가 되어야 겠죠 / 네번의 설문 페이지 후
즉 5페이지까지는 <Mbti />컴포넌트
아니면, <Show /> 결과 페이지
'강의 정리 > React JS' 카테고리의 다른 글
git 머지 관련 오류 .. 셋팅 댓글달지 않게 하기 (0) | 2023.01.28 |
---|---|
2023-01-26 순수 리덕스 과정 (0) | 2023.01.26 |
2023-01-19 / React Redux 첫 수업/ to do list 만들기 (0) | 2023.01.19 |
구조 분해 할당 (0) | 2023.01.18 |
2023-01-17 React Router, redux (0) | 2023.01.17 |