Ming's develop story

Chapter3 - 점수화면 만들기 (3주차) 본문

스파르타코딩클럽 - 항해99/항해99 Chapter3 - react 주특기 기본

Chapter3 - 점수화면 만들기 (3주차)

Ming 2021. 11. 25. 05:09

App.js

import React from "react";
import "./App.css";

import { Route } from "react-router-dom";

import Start from "./Start";
import Quiz from "./Quiz";
import Score from "./Score";

function App() {
  const [name, setName] = React.useState("우민기");

  return (
    <div
      className="App"
      style={{
        maxWidth: "350px",
        margin: "auto",
      }}
    >
      <Route path="/" exact>
        <Start name={name} />
      </Route>

      <Route path="/quiz" exact>
        <Quiz name={name} />
      </Route>

      <Route path="/score" exact>
        <Score name={name} />
      </Route>
    </div>
  );
}

export default App;

Start.js

import React from "react";
import img from "./Teemo.png";

import { useHistory } from "react-router-dom";
import { useDispatch } from "react-redux";
import { setName } from "./redux/modules/user";

const Start = (props) => {
  const history = useHistory();
  const dispatch = useDispatch();
  const name_ref = React.useRef(null);

  return (
    <div
      style={{
        display: "flex",
        height: "100vh", //가운데에 놓기위해 높이를 지정해준다.
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center",
        padding: "16px",
        boxSizing: "border-box",
        //display flex에는 가운데 정렬을 담당하는 두 친구가 있는데
        //align-items: center; 세로줄 하나를 기준으로 모인다. flex가 없으면 가로기준으로 중간정렬을 해준다.
        //justify-content: center;는 flex가 있을땐 위아래로 없을땐 좌우로 정렬을 해준다.
      }}
    >
      <img
        src={img}
        style={{
          width: "60vw",
          margin: "16px",
        }}
      />
      <h1 style={{ fontSize: "1.5em", lineHeight: "1.5" }}>
        나는{" "}
        <span
          style={{
            backgroundColor: "#afe910",
            padding: "5px 10px",
            borderRadius: "30px",
          }}
        >
          {props.name}
        </span>
        에 대해 얼마나 알고 있을까?
      </h1>
      <input
        ref={name_ref}
        style={{
          border: "1px solid #dadafc",
          borderRadius: "30px",
          padding: "10px",
          width: "100%",
        }}
      />
      <button
        onClick={() => {
          dispatch(setName(name_ref.current.value));
          history.push("/quiz");
        }}
        style={{
          padding: "10px 36px", //버튼크기
          backgroundColor: "#dadafc",
          border: "#dadafc",
          borderRadius: "30px",
          margin: "36px 0px",
        }}
      >
        시작하기
      </button>
    </div>
  );
};

export default Start;

Quiz.js

import React from "react";
import img from "./Teemo.png";

import { useHistory } from "react-router";
import { useSelector, useDispatch } from "react-redux"; // 리덕스에서 퀴즈 리스트 가져오기 위해 import
import { addAnswer } from "./redux/modules/quiz";

const Quiz = (props) => {
  const history = useHistory();
  const dispatch = useDispatch();
  const quiz_list = useSelector((state) => state.quiz.quiz_list);
  const user_answer_list = useSelector((state) => state.quiz.user_answer_list);

  // const quiz_list = [
  //   { question: "우민기는 1살이다.", answer: false },
  //   { question: "우민기는 2살이다.", answer: false },
  //   { question: "우민기는 3살이다.", answer: true },
  // ];

  //const [user_answer_list, setAnswerList] = React.useState([]); //강의19분 배열

  const setAnswer = (user_answer) => {
    dispatch(addAnswer(user_answer));
    // setAnswerList([...user_answer_list, user_answer]);
  };

  React.useEffect(() => {
    if (user_answer_list.length === quiz_list.length) {
      // const _score =
      //   (100 / quiz_list.length) *
      //   quiz_list.filter((q, idx) => {
      //     return q.answer === user_answer_list[idx];
      //   }).length; //필터 사용해서 정답 맞춘것만 갯수 골라주고 점수 만들어주기 위해 100/quiz_list.length * 해준다.

      // const score = Math.round(_score);
      // console.log(_score, score);
      history.push("/score");
      return;
    }
  }, [user_answer_list]);

  if (user_answer_list.length === quiz_list.length) {
    return null;
  }

  return (
    <div>
      <p>{user_answer_list.length + 1}번 문제</p>
      <h3>{quiz_list[user_answer_list.length].question}</h3>
      <img
        src={img}
        style={{
          width: "60vw",
          margin: "16px",
        }}
      />

      <div>
        <button
          onClick={() => {
            setAnswer(true);
          }}
          stlye={{
            width: "50px",
            height: "50px",
            margin: "16px",
          }}
        >
          O
        </button>
        <button
          onClick={() => {
            setAnswer(false);
          }}
          stlye={{
            width: "50px",
            height: "50px",
            margin: "16px",
          }}
        >
          X
        </button>
      </div>
    </div>
  );
};

export default Quiz;

Score.js

import React from "react";
import Quiz from "./Quiz";
import { useSelector } from "react-redux";

const Score = (props) => {
  const quiz_list = useSelector((state) => state.quiz.quiz_list);
  const user_answer_list = useSelector((state) => state.quiz.user_answer_list);

  const _score =
    (100 / quiz_list.length) *
    quiz_list.filter((q, idx) => {
      return q.answer === user_answer_list[idx];
    }).length; //필터 사용해서 정답 맞춘것만 갯수 골라주고 점수 만들어주기 위해 100/quiz_list.length * 해준다.

  const score = Math.round(_score);
  console.log(_score, score);
  return (
    <div>
      <h3>
        {props.name} 퀴즈에 대한 내 점수는
        <br />
        {score}
      </h3>

      <p>우와! 참 잘했어요!</p>

      <button>{props.name}에게 한 마디</button>
    </div>
  );
};

export default Score;

index.js

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import store from "./redux/configStore";

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>,
  document.getElementById("root")
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

redux - modules - quiz.js

// 어떤 데이터를 넣을거야 -> 퀴즈 목록 / 유저 정답 목록
// 어떻게 수정도 할거야 -> 유저가 선택한 ox 정답을 정답 목롤에 추가해줄거야!

const ADD_ANSWER = "quiz/ADD_ANSWER"; // 2. 액션 타입

export const addAnswer = (user_answer) => {
  return { type: ADD_ANSWER, user_answer };
}; // 3. 액션 생성 함수

const initialState = {
  quiz_list: [
    { question: "우민기는 1살이다.", answer: false },
    { question: "우민기는 2살이다.", answer: false },
    { question: "우민기는 3살이다.", answer: true },
  ],
  user_answer_list: [],
}; // 1. 초깃값 설정

export default function reducer(state = initialState, action = {}) {
  switch (action.type) {
    case "quiz/ADD_ANSWER": {
      console.log(action);
      const new_user_answer_list = [
        ...state.user_answer_list,
        action.user_answer,
      ];

      console.log(new_user_answer_list);
      return { ...state, user_answer_list: new_user_answer_list }; //...state = 기존에 있던 state유지!
    }

    default:
      return state;
  }
} // 4. 리듀서 제작

redux - modules - user.js

// user 이름을 넣자!
// 점수를 넣자!
// 이름을 바꿔주자!
const SET_NAME = "user/SET_NAME";

export const setName = (name) => {
  return { type: SET_NAME, name };
};

const initialState = {
  user_name: "",
};

export default function reducer(state = initialState, action = {}) {
  switch (action.type) {
    case "user/SET_NAME": {
      console.log(action);
      return { ...state, user_name: action.name };
    }

    default:
      return state;
  }
}

redux - configStore.js

import { createStore, combineReducers } from "redux";
import quiz from "./modules/quiz"; //import 먼저!
import user from "./modules/user";

const rootReducer = combineReducers({ quiz, user });
const store = createStore(rootReducer);

export default store;
//스토어 제작 된 뒤엔 index.js 로 가서 연결해주기!

 

 

결과물

메인 - input에 text를 쓰면 데이터 저장이 됨

 

1~3번 문제
리덕스 활용 점수까지 띄워주기

 

Comments