«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Tags
more
Archives
Today
Total
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Tags
more
Archives
Today
Total
관리 메뉴

코더

react 개념 + react를 이용한 영화 웹 서비스 만들기 본문

카테고리 없음

react 개념 + react를 이용한 영화 웹 서비스 만들기

자바스티안 2024. 5. 23. 15:33

1. usestates와 props

 

-일반적인 javascript 사용-

<!DOCTYPE html>
<html>
<body>
<span> total clicks : 0 </span>
<button id="siu">click me</button>
</body>
<script>
let counter = 0;
const buttons = document.getElementById("siu");
const span = document.querySelector("span");
function clickable() {
console.log("clickkkk");
counter = counter + 1;
span.innerText = `total clicks : ${counter}`;
}
buttons.addEventListener("click",clickable);
</script>
</html>
                                                               
 
 

 

-react(useState)를 사용하여 간결화-


import React from 'react';

function App() {
const [minutes, setMinutes] = React.useState(0);
const [flipped, setFlipped] = React.useState(false);

const onChange = (e) => {
setMinutes(e.target.value); // 입력 값이 변경될 때 상태 업데이트
};

const reset = () => setMinutes(0); // minutes 상태를 0으로 리셋

const onFlip = () => {
reset(); // 상태를 0으로 리셋
setFlipped(!flipped); // flipped 상태를 반전
};

return (
<div>
<h1 className="h1">Super Convert</h1>
<label htmlFor="minutes">Minutes</label>
<input
value={flipped ? minutes * 60 : minutes} // 상태에 따라 값 결정
id="minutes"
placeholder="Minutes"
type="number"
onChange={onChange} // 입력 값 변경 시 상태 업데이트
disabled={flipped} // flipped가 true일 때 입력 필드를 비활성화(###disabled속성이 'true'일 때 비활성화 된다.###)
/>
<button onClick={onFlip}>Flip</button> {/* 버튼을 추가하여 flipped 상태를 토글 */}
<div>
<label htmlFor="hours">Hours</label> //React에서 DOM 속성 이름이 JavaScript의 예약어와 충돌
<input
value={flipped ? minutes : Math.round(minutes / 60)}
id="hours"
placeholder="Hours"
type="number"
disabled={!flipped} // flipped가 false일 때 입력 필드를 비활성화
/>
</div>
<button onClick={reset}>Reset</button> {/* 버튼에 텍스트 추가 */}
<button onClick={onFlip}>Flip</button> {/* 버튼에 텍스트 추가 */}
</div>
);
}

export default App;

 

-props를 사용안할 시-

import React from 'react';

function RedButton() {
return <button style={{ backgroundColor: 'red', color: 'white' }}>Click Me</button>;
}

function GreenButton() {
return <button style={{ backgroundColor: 'green', color: 'white' }}>Click Me</button>;
}

function App() {
return (
<div>
<RedButton />
<GreenButton />
</div>
);
}

export default App;

 

-props- 를 사용할 시

import React from 'react';

function Button(props) {
return (
<button style={{ backgroundColor: props.bgColor, color: 'white' }}>
{props.text}
</button>
);
}

function App() {
return (
<div>
<Button bgColor="red" text="Click Me" />
<Button bgColor="green" text="Submit" />
</div>
);
}

export default App;


 

<Btn text = {value} onClick = {changeValue}  /> 에서 이 onclick은 단지 props에 저장되는것이다 즉 html에서 사용되려면 function Btn({text, onClick}) return ( ~~~~~~ onClick = {onClick}) 이런 식으로 사용해야 한다.(가로 안에onClick이 props이다.)

 

2. prototypes

import PropTypes from "prop-types";
import styles from "./Button.module.css";

function Button({ text }) {
return <button className={styles.title}>{text}</button>;
}

Button.propTypes = {
text: PropTypes.string.isRequired,
};

export default Button;

 

npm install prop-types를 사용해 propTypes가 string이 아닐시(문자열) 경고를 보내게 할 수 있는 등. 코드의 가독성 및 오류를 잡는데 중요하게 사용된다.

 

3.CSS 모듈

import Button from "./Button";
import styles from "./App.module.css";


function App() {
return (
<div>
<h1 className={styles.title}>Welcome back!!!</h1>
<Button text={"Continue"} />
</div>
);
}

export default App;

App.js

.title {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
font-size: 18px;
}

App.module.css

 

위와 같이 css모듈을 사용해 CSS 파일의 클래스를 로컬화(scoped) 해준다. 

===>(css파일에서 .title(변수2) 와 같이 만들고 import된 파일에서는 변수1(styles).title(변수2)와 같이 사용한다.

 

4.useEffect

-useEffect는 우리가 한 번만 실행 할 수 있도록 도와준다.

import Button from "./Button";
import styles from "./App.module.css";
import { useState, useEffect } from "react";


function App() {
const [counter, setValue ] = useState(0);
const onClick = () => setValue((couter) => counter+1);
console.log("kim hyun jun");
useEffect(() => {
console.log("call once");
},[]);
return (
<div>
<h1>{counter}</h1>
<h1>hello</h1>
<button onClick={onClick}>click me</button>
</div>
);
}

export default App;

useEffect(() => { 

},[]);

를 사용해서 한번만 call once가 출력해주도록 해주었다.(당연히 return 값에 useState();를 적용해준것이 아니니 화면에는 찍히지 않고 콘솔창에서 call once가 뜨고 사라진다.

 

5. ...currentArray

import { useState } from "react";

function App() {
const [toDo, setToDo] = useState("");
const [toDos, setToDos] = useState([]);
const onChange = (event) => setToDo(event.target.value);
const onSubmit = (event) => {
event.preventDefault();
if (toDo === "") {
return;
}
setToDos((currentArray) => [toDo, ...currentArray]);
//todo의 값에 ...currentArray을 추가한다. 즉, currentArray에 값이 1,2,3이 들어오면 이 element를 돌려주기 때문에 [todo의 element,1,2,3]으로 들어간다.
//todo = '' 이렇게 쓰지 않는 이유는 직접적으로 state를 고치지 않기 때문이다. 즉,변화하는 settodo("");를 이용해 초기화 시켜준다.
setToDo("");
};
return (
<div>
<h1>My To Dos ({toDos.length})</h1>
<form onSubmit={onSubmit}>
<input
onChange={onChange}
value={toDo}
type="text"
placeholder="Write your to do..."
/>
<button>Add To Do</button>
</form>
</div>
);
}
export default App;

 

6.map

console.log(toDos.map((item, index) => <li key={index}>{item}</li>));
return (
<div>
<h1>My To Dos ({toDos.length})</h1>
<form onSubmit={onSubmit}>
<input
onChange={onChange}
value={toDo}
type="text"
placeholder="Write your to do..."
/>
<button>Add To Do</button>
</form>
<hr />
<ul>
{toDos.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);

첫번째 argument는 value이고(각각의 todo를 의미).두번째 argument는 index이다.

 

7. fetch

const [loading, setLoading] = useState(true);
const [coins, setCoins] = useState([]);
useEffect(() => {
.then((response) => response.json())
.then((json) => {
setCoins(json);
setLoading(false);
});
}, []);

fetch함수가 api를 호출하고 응답(response(호출))를 받으면 JSON 데이터를 받아온다.

받아온 데이터를 setCoins(json)을 통해 상태로 저장된다.

데이터가 불러진 후 로딩 상태를 'false'로 바꾸어준다.

 

8.async/await

const [loading, setLoading] = useState(true);
const [movies, setMovies] = useState([]);
const getMovies = async () => {
const response = await fetch (
);
const json = await. response.json();
setMovies(json.data.movies);
setLoading(false);
};
useEffect(() => {
getMovies();
}, []);

를 더 간단히 만들어 아래와 같이 만든다.

const [loading, setLoading] = useState(true);
const [movies, setMovies] = useState([]);
const getMovies = async () => {
const json = await (
await fetch(
)
).json();
setMovies(json.data.movies);
setLoading(false);
};
useEffect(() => {
getMovies();
}, []);

 

9. route

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Detail from "./routes/Detail";
import Home from "./routes/Home";

function App() {
return (
<Router>
<Routes>
<Route path="/hello" element={<h1>Hello</h1>} />
<Route path="/movie" element={<Detail />} />
<Route path="/" element={<Home />} />
</Routes>
</Router>
);
}

export default App;

-switch문을 더이상 현재 버전에서 쓰지 않기 때문에 중간에 switch를 Routes로 바꾸어 주었고 경로를 Routh path로 이동하게 한 후 element값 즉, js파일을 불러온다.

 

useParams

react-router는 바로 이 변수의 값을 넘겨준다.

import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";

function Detail() {
const { id } = useParams();
const [movie, setMovie] = useState(null); // 영화 정보를 저장
const [loading, setLoading] = useState(true); // 로딩
const [error, setError] = useState(null); // 오류

const getMovie = async () => {
try {
const response = await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`);
if (!response.ok) {
throw new Error("Network response was not ok");
}
const data = await response.json();
setMovie(data.data.movie); // 상태에 영화 정보를 저장
setLoading(false); // 로딩 상태 변경
} catch (error) {
setError(error.message); // 오류 상태 저장
setLoading(false); // 로딩 상태 변경
}
};

useEffect(() => {
getMovie();
}, [id]);

if (loading) return <p>Loading...</p>; // 로딩
if (error) return <p>Error: {error}</p>; // 오류
if (!movie) return <p>No movie data found</p>;

return (
<div>
<h1>{movie.title}</h1>
<p>{movie.year}</p>
<p>{movie.summary}</p>
<img src={movie.medium_cover_image} alt={movie.title} />
<ul>
{movie.genres.map((genre) => (
<li key={genre}>{genre}</li>
))}
</ul>
</div>
);
}

export default Detail;

detail.js 

-영화정보를 저장,로딩,오류 페이지로 나누어 준 후 데이터를 가지고 온다면 setMovie를 통해 저장을 해 준 후, loading 상태를 false로 바꾸어준다,(에러 메시지가 뜰 때고 위와같은 상황을 반복해준다.)

-> 렌더링이 될 때나 id 값의 변화가 있을 때 getMovie();에서 영화에 대한 정보를 가지고 온다.

->가져온 데이터의 genre에 고유 키값을 주어서 렌더링 되거나 id값이 변화할 때 값을 식별하게 해준다.

------------------------------------------------------------------------------------------------------

 

switch문이 react전 버전이라 Route와 element로 바꾸는 것 이외에 어려운점은 없었다.