해당 내용은 노마드 코더의 강의 및 React 공식 문서, 공식문서 번역을 참고하여 작성한 글입니다.

올바르지 않은 내용이 있다면 의견 남겨주세요. 언제든지 환영입니다.

 

1. Movie 컴포넌트

import PropTypes from 'prop-types';

function Movie({key, title, image, summary, genres}) {
    return(
        <div key={key}>
        <h2>{title}</h2>
        <img src={image}/>
        <p>{summary}</p>
        <ul>
          {genres.map((genre, index) => <li>{genre}</li>)}
        </ul>
      </div>
    )
}

Movie.propTypes = {
    image: PropTypes.string.isRequired,
    key:PropTypes.number.isRequired,
    title:PropTypes.string.isRequired,
    summary:PropTypes.string.isRequired,
    genres:PropTypes.arrayOf(PropTypes.string).isRequired
}

export default Movie;

components/Movie.js

 

import { useState, useEffect } from 'react';
import Movie from '../components/Movie';


// reactRouter -> 페이지 전환하는 
function Home() {
  const [loading, setLoading] = useState(true);
  const [movies, setMovies] = useState([]);

  const getMovie = async() => {
    const response = await fetch("https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year");
    const json = await response.json();
    setMovies(json.data.movies);
    setLoading(false);
  }

  useEffect(() => {
    // 과거에 쓰는 방법
    // fetch("https://yts.mx/api/v2/list_movies.json?minimum_rating=9&sort_by=year")
    // .then((response) => response.json())
    // .then((json) => {
    //   setMovies(json.data.movies);
    //   setLoading(false);
    // });

    getMovie();
  }, []);

  return (
    <>
      <h1>Movie</h1>
      { loading? (
        <h1>'Loading..'</h1>
        ) : 
        (
          movies.map((item) => 
          <Movie key={item.id} title={item.title} image={item.medium_cover_image} summary={item.summary}
          genres={item.genres}/>
          )
        )
      }
    </>
  );
 
}

export default Home;

routes/Home.js

 

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    
  );
}

export default App;

App.js

 

App.js는 비워두고 처음 시작시 Movie 리스트가 보여지고, url 변경 시 detail을 보여줄 수 있도록 수정한다. 이것을 위해 react-router를 이용한다.

 

2. react-router

"클라이언트 측 라우팅",  기존 웹사이트에서 브라우저는 사용자가 링크를 클릭하면 새 페이지에 대한 프로세스가 처음부터 시작된다. 반면, 클라이언트 측 라우팅을 통해 앱은 서버에서 다른 문서를 요청하지 않고도 링크 클릭을 통해 URL을 업데이트 할 수 있다. 

브라우저가 완전히 새로운 문서를 요청하거나 다음 페이지에 대한 CSS, JS 자산을 재평가할 필요가 없기 때문에 더 빠른 사용자 경험이 가능하다.

react 와 <a> 렌더링 차이

 

그러면 제목 클릭 시, Detail 페이지로 넘어가는 코드를 작성해본다.

import logo from './logo.svg';
import './App.css';
import { Route, Routes, BrowserRouter } from "react-router-dom";
import Home from './routes/Home';
import Detail from './routes/Detail';


function App() {
  return (
    <div>
      <h1>Movie Router</h1>
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/movie/:thisismovieId" element={<Detail />} />
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;

App.js

 

import PropTypes from 'prop-types';
import { Link } from "react-router-dom";

function Movie({id, title, image, summary, genres}) {
  console.log(`${id} :: title is ${title}`);
    return(
        <div key={id}>
          <h2><Link to={`/movie/${id}`}>{title}</Link></h2>
          <img src={image}/>
          <p>{summary}</p>
          <ul>
            {genres.map((genre, index) => <li key={index}>{genre}:: {index}</li>)}
          </ul>
      </div>
    )
}

Movie.propTypes = {
    image: PropTypes.string.isRequired,
    id:PropTypes.number.isRequired,
    title:PropTypes.string.isRequired,
    summary:PropTypes.string.isRequired,
    genres:PropTypes.arrayOf(PropTypes.string).isRequired
}

export default Movie;

Movie.js

 

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

const getDetail = async(id) => {
    const response = await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`);
    const json = await response.json();
    console.log(json);
}
function Detail() {

    // 전달한 param 가져오기
    // <Route path="/movie/:thisismovieId" element={<Detail />} /> thisismovieId가 찍히게 된다.
    const { thisismovieId } = useParams();
    console.log(thisismovieId);

    useEffect(()=> {
        getDetail(thisismovieId);
    }, []);
    return (<h1>Detail!</h1>)
}

export default Detail;

Detail.js

 

  • <Routes> : <Routes>는 모든 하위 경로를 탐색하여 가장 적합한 일치 항목을 찾아 렌더링한다. 
  • <Route>
    • 라우터 생성 함수에 전달되는 개체
    • <Route path = "/teams/:teamId">
      • path는 URL과 일치하는 경로이다. URL, href 와 일치하는지 확인한다. 
      • : 는 동적세그먼트다. 경로가 URL과 일치하면 동적 세그먼트는 URL에 파싱한다. 이 세그먼트는 useParams() 에서 가져올 수 있으며 - 는 사용할 수 없다.
        🚫 "/ teams-:teamId" 
        🚫 "/:category--:productId" 

'Web > React' 카테고리의 다른 글

[ReactJS로 영화 웹 서비스 만들기] 기본문법  (0) 2024.10.17

해당 내용은 노마드 코더의 강의 및 React 공식 문서, 공식문서 번역을 참고하여 작성한 글입니다.

올바르지 않은 내용이 있다면 의견 남겨주세요. 언제든지 환영입니다.

 

1. JS vs React

<!DOCTYPE html>
<html>
	<body>
		<span>Total clicks: 0</span>
		<button id="btn">click me</button>
	</body>
	<script>
		let counter = 0;
		const button = document.getElementById("btn");
		const span = document.querySelector("span");
		function handleClick() {
			counter = counter + 1;
			span.innerText = `Total clicks: ${counter}`;
		}
		button.addEventListener("click", handleClick)
	</script>
</html>

count Javascript 코드

<!DOCTYPE html>
<html>
	<body>
		<div id="root"></div>
	</body>
	<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
	<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
	<script>
		// 어려운 방식 react의 동작방법을 알기 위한 방식
		const root = document.getElementById("root");
		// reactJS는 유저에게 보여질 내용을 컨트롤 할 수 있음
		// reactJS는 javascript로 그리고 html로 번역
		//const span = React.createElement("span", {id: "rabong-span", style: {color: "orange"}}, "hello i'm burabong");
		// reactdom은 reactelement를 html로 바꿔준다, reactJs는 엔진
		
		const span = React.createElement("span", null, "hello i'm burabong");
		const button = React.createElement("button", {
			onClick:() => console.log('im clicked'),
			style: {
				backgroundColor: 'yellow'
			}
		}, "Click me"); // {} 프로퍼티에 이벤트도 등록 가능하다.
		const container = React.createElement("div", null, [span, button]); // div 안에 span, button 같이 들어가기 위함
		
		ReactDOM.render(container, root); // container root안에 렌더링 해줘

	</script>
</html>

버튼 클릭 시 숫자세기 - 복잡한 React 코드

 

JavaScript 처럼 html을 생성하고 그 다음 이벤트를 추가하는 것이 아닌, React.createElement()를 통해 html 생성 및 프로퍼티, 이벤트를 한번에 만들고 있음을 확인 할 수 있다.

<!DOCTYPE html>
<html>
	<body>
		<div id="root"></div>
	</body>
	<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
	<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
	<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
	<script type="text/babel">
		const root = document.getElementById("root");

		// 이렇게 쓰는 방식을 JSX
		// 브라우저가 JSX를 이해하기 위해서 Babel 이용해 변환해준다
		function Span() {
			return (<span>hello i'm burabong</span>);
		}
		// const Span = () => (<span>hello i'm burabong</span>); 위와 똑같음
		const Button = () => (<button style={{
				backgroundColor: 'yellow'
			}} onClick={() => console.log('im clicked')

			}>Click me</button>);
		
		// 컴포넌트의 첫글자는 무조건 대문자, 안그러면 react, jsx는 html 태그라고 인식한다.
		const Container =() => (
			<div> 
				<Span/>
				<Button/> 
			</div>
		)
		
		ReactDOM.render(<Container/>, root); // container root안에 렌더링 해줘
	</script>
</html>

버튼 클릭 시 숫자세기 - JSX를 이용한 React 코드

  • JSX : JavaScript를 확장한 문법, HTML과 비슷하게 마크업을 작성할 수 있도록 해준다. 또한 CamelCase로 작성해야 하며 변수명에 대시를 포함하거나 class처럼 예약어를 사용할 수 없다. 다만 aria-*, data-* 어트리뷰트는 HTML과 동일하게 대시 사용하여 작성할 수 있다.
  • Babel: JavaScript 컴파일러, 주로 EMCAScript 2015+ 코드를 이전 버전의 JavaScript로 변환하는 데 사용되는 도구 체인이다. 이런 Babel은 JSX도 변환해줄 수 있다.

개발자 도구 통해서 본 BABEL 컴파일
버튼 클릭 시 숫자세기 - 좋은 코드①

 

<!DOCTYPE html>
<html>
	<body>
		<div id="root"></div>
	</body>
	<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
	<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
	<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
	<script type="text/babel">
		const root = document.getElementById("root");

		// state는 데이터가 기본적으로 저장되는 곳
		function App() {
			
			console.log(React.useState(0));
			// 배열을 한번에 빼내기 위해서
			// modifier(=setCounter)가지고 state(=counter)를 변경할 때 컴포넌트 재 생성, 새로운 값 가지고 리렌더링되는 것
			// 데이터가 바뀔 때마다 컴포넌트 리렌더링하고 UI refreash하는 거다 
			let [counter, setCounter] = React.useState(0);
			const onClick=()=> {
                // counter = counter + 1은 내가 원하는 값이 나오지 않을 수 있다. 다른 곳에서 써버릴 수 있으니까
				// 이전값을 가지고 값 변화해주고 싶다면 함수를 이용한다.
				setCounter((current) => current + 1); 
			}
			return (
				<div> 
					<span>Total clicks: {counter}</span>
					<button id="btn" onClick={onClick}>click me</button>
				</div>
			)
		}
	
		ReactDOM.render(<App/>, root); 
	</script>
</html>

 

  • useState:
    • 컴포넌트에 state 변수를 추가 할 수 있는 React Hook
    • useState(InitialState), 해당 결과값이 배열이므로 const [age, setAge] = React.useState(28); 처럼 배열 구조 분해를 사용하여 변수의 이름 지정하는 것이 규칙이다.
    • 정확히 두개의 값을 가진 배열 반환한다. 첫번째는 초기 state값, 두번째는 다른 값으로 업데이트하고 리렌더링을 촉발할 수 있는 set 함수다. set 함수는 반환값이 없다.
    • 반복문이나 조건문 안에서는 호출할 수 없다.

2. Converter 

<!DOCTYPE html>
<html>
	<body>
		<div id="root"></div>
	</body>
	<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
	<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
	<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
	<script type="text/babel">
		const root = document.getElementById("root");

		function App() {
			const [amount, setAmount] = React.useState(0);
			const [inverted, setInverted] = React.useState(false);


			// 입력한값으로 변경시켜 주고 싶어
			const onChange = (e) => {
				console.log(e.target.value);
				setAmount(e.target.value);
			}
			const onReset = () => setAmount();
			const onFlip = () => {
				onReset();
				setInverted((current) => !current);
			}
			return (
				<div> 
					<h1>Super Converter</h1>
					<label htmlFor="minutes">Minutes</label>
					<input value={inverted? amount * 60 : amount} id="minutes" placeholder="Minutes" type="number" onChange={onChange} disabled={inverted}/>
					<h1>you want convert {amount}</h1>
					<label htmlFor="hours">Hours</label>
					<input value={inverted? amount : Math.round(amount/60)} id="hours" placeholder="Hours" type="number" disabled={!inverted} onChange={onChange}/>
					<button onClick={onReset}>reset</button>
					<button onClick={onFlip}>Flipped</button>
				</div>
				
			)
			// label을 input과 연결시키기 위해 for="(inputId)" 그러면 label 클릭시 input 활성화가 된다.
		}
	
		ReactDOM.render(<App/>, root); 
	</script>
</html>

 

converter - react①

'Web > React' 카테고리의 다른 글

[ReactJS로 영화 웹 서비스 만들기] 기본 기능  (1) 2024.10.23

+ Recent posts