과제 : App06.js 실습하며 정리
jsx와 useState 익숙해지기
lotto.html (js) -> react 애플리케이션으로 변경하기 (스타일 커스터마이징)
리액트애플리케이션이 실행될때 가장먼저실행되는 진입점(entrypoint)
역할 을수
행한다.
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "../src/App06";
import reportWebVitals from "./reportWebVitals";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// 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();
여기에서 보여줄 최초 컴포넌트를 import하고
javascript(node)로 작성한 소스코드를 react.js 로 변환하기
addUrl.js
정적 파일인 HTML, CSS 및 JavaScript 파일을 서비스하는 간단한 웹 서버
const http = require("http");
const fs = require("fs");
const url = require("url");
var morgan = require("morgan");
var logger = morgan("tiny");
const hostname = "127.0.0.1"; // localhost
const port = 3000;
const server = http.createServer(function (req, res) {
//서버 앱 내에서 접근할 경로를 해석한다
const pageURL = req.url;
const pathname = url.parse(pageURL, true).pathname;
logger(req, res, function (err) {
if (err) return console.log(err);
if (pathname === "/") {
fs.readFile("./public/lotto.html", function (err, data) {
res.statusCode = 200;
res.writeHead(200, { "Content-Type": "text/html" });
res.end(data);
});
} else if (pathname === "/style.css") {
fs.readFile("./public/style.css", "utf8", function (err, data) {
res.writeHead(200);
res.write(data);
res.end();
});
} else if (pathname === "/script.js") {
fs.readFile("./public/script.js", "utf8", function (err, data) {
res.writeHead(200);
res.write(data);
res.end();
});
}
});
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
//lotto.html -->로또번호 6자리 랜덤추첨기능
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>로또 추첨 게임</title>
<link href="style.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="lotto">
<h3><span id="today"></span>로또 번호 추첨</h3>
<div class="numbers"></div>
<button id="draw">추첨</button><button id="reset">다시</button>
</div>
</div>
<script src="script.js"></script>
</html>
App06.js
import { useState } from "react";
import "./App06.css";
function App() {
//useState 를 사용하여 상태 관리
// lottoNumbers: 로또 번호를 저장하는 배열
//setLottoNumbers: lottoNumbers 배열의 값을 업데이트하는 함수
const [lottoNumbers, setLottoNumbers] = useState([]);
// 현재날짜 가져오기
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth() + 1;
const date = today.getDate();
const now = `${year}년 ${month}월 ${date}일 `;
return (
<div className="container">
<div className="lotto">
<img src="/lottery.png" alt="money"></img>
<h3>
<span>{now}</span>
</h3>
<div className="title">로또 번호 추첨</div>
<div className="numbers">
{lottoNumbers.map((num, idx) => {
return (
<div className="eachnum" key={idx}>
{num}
</div>
);
})}
</div>
//"추첨" 버튼 클릭 시 로또 번호 추첨: lottoNumbers 배열을 빈 배열로 초기화한다.
<button
onClick={() => {
//여기서 왜 또 지역변수로 배열을 선언해야 하는지 의문이 있었는데
setLottoNumbers 함수는 이전 lottoNumbers 배열의 상태를 변경하는 것이 아니라
새로운 배열을 할당해야 한다. 그렇지 않으면 React는 상태가 변경되지 않았다고
감지하여 화면을 업데이트하지 않을 수 있다.
따라서 setLottoNumbers 함수를 호출할 때
새로운 배열을 생성하여 상태를 업데이트해야 합다고 알게되었다.
const lottoNumbers = [];
while (lottoNumbers.length < 6) {
let ran = Math.floor(Math.random() * 45) + 1;
if (lottoNumbers.indexOf(ran) === -1) {
lottoNumbers.push(ran);
}
}
setLottoNumbers(lottoNumbers);
}}>
추첨
</button>
<button
onClick={() => {
setLottoNumbers([]);
}}>
다시
</button>
</div>
</div>
);
}
export default App;
스타일은 같은 경로에 App06.css
파일을 만들어 링크
@charset "utf-8";
@font-face {
font-family: 'CookieRun-Regular';
src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2001@1.1/CookieRun-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
}
*{
font-family: 'CookieRun-Regular';
box-sizing: border-box;
color: #ffffff
}
html{
font-size: 32px;
}
body{
margin: 0;
}
.container{
width: 500px;
height: 100vh;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
background: #1B1926;
}
img {
margin-top: 30px;
}
.lotto{
width: 420px;
height: 800px;
text-align: center;
//배경색 그래디언트
background: linear-gradient(to bottom right, #3747A6, #BF2011);
border-radius: 50px;
}
h3 {
margin: 20px 0;
}
.numbers{
width: 420px;
padding: 1rem 1.2rem;
display: flex;
flex-wrap : wrap;
justify-content: space-around;
align-items: center;
}
.eachnum{
font-size: 0.75em;
width: 40px;
height: 40px;
border: 1px solid white;
border-radius: 25px;
padding: 1.1rem;
margin: 10px;
margin-bottom: 20px;
color: white;
/* background-color: red; */
display: flex;
justify-content: center;
align-items: center;
//그림자 효과
box-shadow: 0 0 10px 0px rgba(255, 255, 255, 0.9),
0 0 1px 5px rgba(255, 255, 255, 0.1),
0 0 5px 10px rgba(255, 255, 255, 0.2),
0 0 30px 15px rgba(255, 255, 255, 0.0),
0 10px 30px 20px rgba(255, 255, 255, 0.1);
}
button{
font-size: 0.9em;
width: 40%;
height: 1.8rem;
border: none;
border-radius: 16px;
color: #1B1926;
background-color: #F2BC57;
cursor: pointer;
margin-right: 10px;
text-align: center;
}
button:active{
font-size: 0.6em;
width: 105px;
height: 42px;
}
완성 결과
npm start