MBTI 구현 마저하기
Check 액션 생성 함수 삽입
mbti 조사 결과 값을 만들어주기 위해 선택한 값을 바탕으로 Action 시켜준다.
export function check(result) {
return {
type: CHECK,
payload: { result },
};
}
export default function mbti(state = initState, action) {
switch (action.type) {
case CHECK:
return {
...state,
mbtiResult: state.mbtiResult + action.payload.result,
};
case NEXT:
return {
...state,
page: state.page + 1,
};
case RESET:
return {
...state,
page: 0,
mbtiResult: '',
};
default:
return state;
}
}
dispatch() 함수에 check() 를 넘겨주되, survey 안에 존재하는 result(엠비티아이 문자열) 를 넘겨준다.
return (
<>
<SurveyQuestion>{survey[page - 1].question}</SurveyQuestion>
<ul>
{survey[page - 1].answer.map((e, idx) => {
return (
<li key={idx}>
<SkyblueButton
text={e.text}
clickEvent={() => {
dispatch(check(e.result));
dispatch(next());
}}
/>
{idx === 0 && <Vs>VS</Vs>}
</li>
);
})}
</ul>
<Progress page={page} maxPage={survey.length} />
</>
);
설정하고 리덕스 개발툴을 활용하여
변화값을 확인할 수 있다.
결과를 출력하는 페이지
const Header = styled.p`
font-size: 3em;
`;
const Explanation = styled.p`
font-size: 1.5em;
color: #777;
`;
const Result = styled.p`
font-size: 3em;
color: dodgerblue;
`;
const Additional = styled.p`
font-size: 2em;
color: orange;
`;
const AdditionalImg = styled.img`
width: 500px;
transform: translateX(-35px);
`;
export default function Show() {
const result = useSelector((state) => state.mbti.mbtiResult);
const explanation = useSelector((state) => state.mbti.explanation[result]);
const dispatch = useDispatch();
return (
<>
<Header>당신의 개발자 MBTI 결과는?</Header>
<Explanation>{explanation.text}</Explanation>
<Result>{result}</Result>
<Additional>이건 재미로 읽어보세요</Additional>
<AdditionalImg src={explanation.img} alt="팩폭"></AdditionalImg>
<PinkButton text="다시 검사하기" clickEvent={() => dispatch(reset())} />
</>
);
}
결과화면 분기 처리
function App() {
const page = useSelector((state) => state.mbti.page);
const survey = useSelector((state) => state.mbti.survey);
return (
<>
<GlobalStyle />
<Main>
{page === 0 ? <Start /> : page > survey.length ? <Show /> : <Mbti />}
</Main>
</>
);
}
일단 리액트로 구현할 수 있는 부분은 끝났다!
MongoDB와 연동하여 응용하기
데이터가 객체형태나 배열형태인 경우 MySQL 보다 좋다.
백엔드 시작 전 기초 세팅하기
// .env 파일
PORT = 4000
MONGO_DB_URI = "mongodb+srv://아이디:비밀번호@cluster0.y4isdtc.mongodb.net/?retryWrites=true&w=majority"
1. npm i -S express core dotenv mongodb 설치
2. MongoDB 클라우드 -> Connect 부분 카피해서 몽고DB와 접속 모듈 생성
const { MongoClient, ServerApiVersion } = require('mongodb');
const { MONGO_DB_URI } = process.env;
const client = new MongoClient(MONGO_DB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
serverApi: ServerApiVersion.v1,
});
module.exports = client;
3. 아틀라스 클라우드에 Database 생성 후 counts 로 방문자수 컬렉션을 만들어준다.
4. controller 와 routes 기본 설정
// dataController.js 데이터 관련된 컨트롤러
const mongoClient = require('./mongoConnect');
const initState = {
// 넣어줄 데이터
};
const setData = async (req, res) => {
try {
const client = await mongoClient.connect();
const data = client.db('mbti').collection('data');
await data.insertOne(initState);
res.status(200).json('데이터 추가 성공');
} catch (err) {
console.log(err);
res.status(500).json('데이터 삽입 실패, 알 수 없는 문제 발생');
}
};
module.exports = {
setData,
};
몽고클라이언트를 연결하고 이미 존재하는 data 를 post 형식으로 몽고DB에 insertOne() 해준다.
// 서버 라우터 data.js
const express = require('express');
const router = express.Router();
const { setData } = require('../controllers/dataController');
router.post('/setdata', setData);
module.exports = router;
// 메인 서버에 라우터 연결
const express = require('express');
const cors = require('cors');
require('dotenv').config();
const PORT = process.env.PORT;
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cors());
const dataRouter = require('./routes/data');
app.use('/data', dataRouter);
app.listen(PORT, () => {
console.log(`서버가 ${PORT}번에서 작동 중입니다.`);
});
POSTMAN 으로 요청 보내기
컨트롤러 기능 추가
- 방문자 수를 가져오는 getCounts
const getCount = async (req, res) => {
try {
const client = await mongoClient.connect();
const countsDB = client.db('mbti').collection('counts');
const counts = await countsDB.findOne({ id: 1 });
res.status(200).json(counts);
} catch (err) {
console.error(err);
res.status(500).json('데이터 가져오기 실패, 알 수 없는 문제 발생');
}
};
- 방문자 수를 증가시키는 incCount
const getCount = async (req, res) => {
try {
const client = await mongoClient.connect();
const countsDB = client.db('mbti').collection('counts');
const counts = await countsDB.findOne({ id: 1 });
res.status(200).json(counts);
} catch (err) {
console.error(err);
res.status(500).json('데이터 가져오기 실패, 알 수 없는 문제 발생');
}
};
const incCount = async (req, res) => {
try {
const client = await mongoClient.connect();
const countsDB = client.db('mbti').collection('counts');
await countsDB.upDateOne(
{ id: 1 },
{
$inc: { counts: +1 },
},
);
res.status(200).json('방문자수 업데이트 성공');
} catch (err) {
console.error(err);
res.status(500).json('방문자수 가져오기 실패, 알 수 없는 문제 발생');
}
};
- 데이터를 받아오는 getData
const getData = async (req, res) => {
try {
const client = await mongoClient.connect();
const data = client.db('mbti').collection('data');
const mbtiData = await data.find({}).toArray();
res.status(200).json(mbtiData);
} catch (err) {
console.error(err);
res.status(500).json('데이터 가져오기 실패, 알 수 없는 문제 발생');
}
};
데이터 라우팅 추가해주기
const express = require('express');
const router = express.Router();
const {
setData,
getData,
incCount,
getCount,
} = require('../controllers/dataController');
router.post('/setdata', setData);
router.get('/getdata', getData);
router.get('/getcount', getCount);
router.post('/inccount', incCount);
module.exports = router;
리액트와 몽고DB 연동
리액트에서 몽고DB의 데이터를 받는 함수 작성하기
위 백엔드에서 작성해준 DB 데이터를 받아주려면 fetch() 로 받아오고,
가장 처음 마운트 될 때 데이터를 받아와야 하므로, Start 컴포넌트 안 useEffect() 로 fetchData() 함수를 작성해준다.
export default function Start() {
const dispatch = useDispatch();
async function fetchData() {
// 백엔드 쪽에서 데이터 요청하기
const resMbtiData = await fetch('http://localhost:4000/data/getdata');
if (resMbtiData.status === 200) {
const data = await resMbtiData.json();
console.log(data);
} else {
// throw new Error('통신 오류');
console.log(await resMbtiData.json());
}
}
// Mount 될 때 실행
useEffect(() => {
fetchData();
}, []);
return (
<>
<Header>개발자 MBTI 조사</Header>
<MainImg src="/images/main.jpg" alt="메인 이미지" />
<SubHeader>
개발자가 흔히 접하는 상황에 따라서 MBTI를 알아봅시다.
</SubHeader>
<OrangeButton text="테스트 시작" clickEvent={() => dispatch(next())} />
</>
);
}
받아온DB 정보를 활용한 리덕스 구조 변경
원래의 더미데이터를 없애고 빈 state 를 만들어준다.
const initStateEmpty = {
mbtiResult: '',
page: 0,
survey: [],
explanation: {},
};
// Action 타입 설정
const INIT = 'mbti/INIT';
// Action 생성 함수 설정
export function init(data) {
return {
type: INIT,
payload: data,
};
}
리듀서도 수정해줌
export default function mbti(state = initStateEmpty, action) {
switch (action.type) {
case INIT:
return {
...state,
survey: action.payload.survey,
explanation: action.payload.explanation,
};
case CHECK:
return {
...state,
mbtiResult: state.mbtiResult + action.payload.result,
};
case NEXT:
return {
...state,
page: state.page + 1,
};
case RESET:
return {
...state,
page: 0,
mbtiResult: '',
};
default:
return state;
}
읽어온 DB를 다시 리덕스 안에 넣어서 출력해주기
async function fetchData() {
const resMbtiData = await fetch('http://localhost:4000/data/getdata');
if (resMbtiData.status === 200) {
const data = await resMbtiData.json();
if (data[0]) dispatch(init(data[0]));
console.log(data);
} else {
// throw new Error('통신 오류');
console.log(await resMbtiData.json());
}
}
받아온 data 는 결국 큰 구조상 배열의 첫번째 요소이므로 data[0] 으로 접근해야 하는 것이다.
방문자수 값을 첫 화면(Start)에 전달
counts 는 값을 새로 받으면 Start 컴포넌트의 방문자 수를 Update 해줘야 하므로 useState 로 값을 선언해준다.
State 값을 변경하는 Hook에 원하는 값을 전달한다.
async function fetchCounts() {
const resCountsData = await fetch('http://localhost:4000/data/getcount');
if (resCountsData.status === 200) {
const countsData = await resCountsData.json();
console.log(countsData);
if (countsData.counts !== undefined) setCounts(countsData.counts);
} else {
console.log(resCountsData.json());
}
}
마지막 페이지에서 Counts+1 해주기
const incCount = async () => {
const resInc = await fetch('http://localhost:4000/data/inccount', {
method: 'post',
});
if (resInc.status === 200) {
console.log(await resInc.json());
} else {
// throw new Error('통신 이상');
console.log(await resInc.json());
}
};
마지막 페이지인 Show 컴포넌트가 나온다는 것은 테스트를 마친 것이므로 방문자수를 여기서 useEffect() 로 늘려주면 된다.
'학원에서 배운 것 > React' 카테고리의 다른 글
우당탕탕.. 팀프로젝트 리액트로 드래그 앤 드롭 구현하기 (0) | 2023.04.12 |
---|---|
KDT 5th 웹개발자 입문 수업 ... 마지막 팀 프로젝트 시작! (0) | 2023.04.08 |
KDT 5th 웹개발자 입문 수업 43일차 - 2 (0) | 2023.04.05 |
KDT 5th 웹개발자 입문 수업 43일차 - 1 (0) | 2023.04.05 |
KDT 5th 웹개발자 입문 수업 42일차 (0) | 2023.04.04 |