일반적으로 바닐라 자바스크립트는 폭포 모델로, 위에서 아래로 순차적으로 실행되며, 한 번에 하나의 작업만 처리된다.
html 구조를 만들어 Dom요소에 접근해 Dom을 조작하는 방식이다.
이런건 너무 인터렉티브하지 않기에 리액트JS가 나오게 되었다.
참고로 리액트는 가상돔을 사용하고 상태(state)가 변경되었을 시 컴포넌트 상태가 업데이트 되는데 이말은 정리된거 다보고 다시보면 이해가 될거다.
❓리액트가 뭔가?
결론만 말하면, 바닐라 자바스크립트랑 반대로 기능을 통해 HTML을 생성하고 렌더링할 수 있는 라이브러리다
즉, 자바스크립트로 html태그를 만들 수 있다는 뜻
❓어떻게 자바스크립트에서 html을 만들 수 있나?
JSX라는 문법을 사용하여 JavaScript 코드 안에서 HTML과 유사한 태그 구문으로 UI를 작성할 수 있도록한다.(단, 바벨을 필수로 설치해야한다.)
평소 npx create react app 명령어를 통해서 곧바로 리액트 초기설정을 해서 모르겠지만, 명령어 없이 라이브러리로만 추가해서 사용해 보면 왜 이 코드가 명령어를 사용했을때 있는지 알 수 있다.
jsx는 자바스크립트 코드안에서 html과 유사한 태그 구문을 사용할 수 있게 하는거라고 했는데 jsx없이 리액트 js만으로 UI를 만드는법과, jsx를 사용해서 UI를 만드는 법을 먼저 알아보자
📌ReactJS
📌React-dom이란?
📌컴포넌트란?
→ 반환하는 함수가 컴포넌트인건 아님, 반환되는 Object가 컴포넌트인 개념으로 생각해야함.
→ 리액트의 구성하는 요소(UI)들 중에서 가장 작은 단위
📌<자바스크립트를 이용해 html을 넣는 방식(기존의 html→ JS의 반대 방식)>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<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>
const root = document.getElementById("root"); //span 태그가 들어갈 영역지정
const spantag = React.createElement("span"); //span 엘리먼트생성
ReactDOM.render(spantag, root); //root안에 span태그를 집어넣겠다(랜더하겠다.)
</script>
</html>
const spantag = React.createElement("span", { id: "sein" ,style:{color:"red"},"hello");
ReactDom.rener(spantag,root)//루트안에 spantag를 랜더링 하겠다.
//이벤트 작성
const btn = React.createElement(
"button",
{ id:"title",
style:{color:"red"},
onClick: () => console.log("i'm clicked"),
},
"Click me"
);
//형식
const title = (
<h3 id="title" onMouseEnter={()=> console.log("mouse enter")}>
hello
</h3>
);
//기존 jsx없이 쓰는 reactJS
const btn = React.createElement(
"button",
{
id: "title",
style: { backgroundColor: "yellow", borderColor: "transparent" },
onClick: () => console.log("i'm clicked"),
},
"Click me"
);
🔽//jsx로 변환,bable 사용해야함
const Button = <button style={{ backgroundColor: "yellow", borderColor: "transparent" }}
onClick = {() => console.log("i'm clicked")}> Click me</button>
🔽//함수로써 사용하려면, 함수를 정의해주고, <첫글자 대문자 태그/>
const Title = ()=> (
<h3 id="title" onMouseEnter={()=> console.log("mouse enter")}>
hello
</h3>
);
const Container = ()=> <div><Title/> <Botton/></div>
ReactDOM.render(<Container />, root);
React.createElement("h3")
type=text/babel
을 적어줘야 함/*원래는 위에서 <Title/> <Button/>으로 연결시켰쥬 이런
복잡하게 기존의 함수 컴포넌트를 를 만들고 </>를 통해 랜더링해 주고가
아닌, 바로 안에 태그를 넣어주는 방식*/
<script type="text/babel">
const Container = () => (
<div>
<h3>점수:0</h3>
<button>Click me</button>
</div>);
ReactDOM.render(<Container />, root);
</script>
const x =[1,2,3]
const a = x[0]; //1
const b = x[2]; //3
🔽구조분해할당
const x =[1,2,3]
const [a,b,c]= x; //a = 1, b = 2, c = 3
setState((현재값)⇒ 계산식);
⇒ setState((current)⇒current+1);📌even.target.value
function App() {
const [index, setIndex] = React.useState(0);
const onSelect = (event) => {
setIndex(event.target.value);
};
return (
<div>
<h1>super convertor</h1>
<select value={index} onChange={onSelect}>
<option value="0">minutes or Hours</option>
<option value="1">km or miles</option>
</select>
</div>
);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>바닐라 자바스크립트</title>
</head>
<body>
<span>total:0</span>
<button id="btn">click</button>
<script>
let count = 0;
const button = document.getElementById("btn");
const span = document.querySelector("span");
function handleClick() {
console.log("click perfect");
count = count + 1;
span.innerText = `total:${count}`;
}
button.addEventListener("click", handleClick);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ReactJS</title>
</head>
<body>
<div id="root"></div> // 최상단 루트는 지정해 줘야함.
<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>
<!--1. react먼저 import -->
<script>
const root = document.getElementById("root");
const spantag = React.createElement(
"span",
{ id: "sexy-span", style: { color: "red" } },
"Hello"
);
//react를 import 했기 때문에 create함수를 가진 React object를 사용할 수 있다.
//안에들어갈 내용은 태그 이름과 같아야 한다.
//ReactJs가 body안에 HTML을 생성(reactdom libray필요)
//1.argument는 태그 이름 두번째는 프로퍼티가 들어갈 수 있다.(classname, id,이벤트)
//세번째는 내용
ReactDOM.render(spantag, root);
//render react element를 가지고 html로 만들어 배치한다.(사용자에게 보여준다.)
//결론:reactjs는 유저에게 보여질 내용을 컨트롤 할 수 있다.
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ReactJS_addEvent</title>
</head>
<body>
<div id="root"></div>
<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>
//프로퍼티를 통해서 이벤트를 추가 할 수 있다.
const root = document.getElementById("root");
const h3tag = React.createElement(
"h3",
{
onMouseEnter: () => console.log("mouse enter"),
},
"Hello"
);
const btn = React.createElement(
"button",
{
onClick: () => console.log("i'm cliked"),
},
"click me"
);
//두개를 동시에 랜더하고싶다면
const container = React.createElement("div", null, [h3tag, btn]);
// ReactDOM.render(btn, root);
ReactDOM.render(container, root);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<!-- 편리하기 위하여 createElement대신 jsx사용 -->
<!-- 1.리액트 요소를 만들 수 있다. 2.자바스크립트의 확장문법 -->
<!-- html과 비슷해서 편라한 것 대신 번역 프로그램 babel이 필요하다 -->
<body>
<div id="root"></div>
<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");
const Title = (
<h3 id="title" onMouseEnter={() => console.log("mouse enter")}>
hello i was h3tag
</h3>
);
const Button = (
<button
style={{ backgroundColor: "red" }}
onClick={() => {
console.log("i'm cliked");
}}
>
click me
</button>
);
const container = React.createElement("div", null, [Title, Button]);
ReactDOM.render(container, root);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>without createElement</title>
</head>
<!-- state: 데이터가 저장되는곳: 바뀌는 값들 -->
<body>
<div id="root"></div>
<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");
// const container = React.createElement("div", null, [Title, Button]);
const Container = () => (
<div>
<h3>hello i'm title</h3>
<button
style={{ backgroundColor: "red" }}
onClick={() => {
console.log("i'm cliked");
}}
>
click me
</button>
</div>
);
ReactDOM.render(<Container />, root);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>without createElement</title>
</head>
<!-- 컴포넌트를 분리하는 작업/컴포넌트를 다른 컴포넌트에 넣는다 -->
<!-- create element 대신 함수를 만들고 불러오는 작업, 대문자로 시작해야함-->
<!-- html과 비슷해서 편라한 것 대신 번역 프로그램 babel이 필요하다 -->
<!-- 재사용 함수를 사용하기 위한 과정 without createElement -->
<body>
<div id="root"></div>
<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");
const Title = () => (
<h3 id="title" onMouseEnter={() => console.log("mouse enter")}>
hello i was h3tag
</h3>
);
const Button = () => (
<button
style={{ backgroundColor: "red" }}
onClick={() => {
console.log("i'm cliked");
}}
>
click me
</button>
);
// const container = React.createElement("div", null, [Title, Button]);
const Container = () => (
<div>
<Title />
<Button />
</div>
);
ReactDOM.render(<Container />, root);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>bad example to state</title>
</head>
<!--직접화면에 렌더링하기
화면에 어떻게 업데이트 되는지 원리를 파악하기 위한 정도 :render함수를 추가한다 -->
<body>
<div id="root"></div>
<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");
let counter = 0;
//이전 js에서는 counter을 넣기위해 innertext를 사용했다. span.innerText = `total:${count}`;
//리액트에서는 중괄호를 열어주고 변수 이름을 담으면 된다.
function countUp() {
counter = counter + 1;
render();
}
function render() {
ReactDOM.render(<Container />, root);
}
// 이떄까지는 랜더링한 부분만 있는 거지 UI에서 볼 수 있도록 리랜더링 하는게 없었다
// 한마디로 countUP함수를 부를 때마다 render될 수 있도록..!
// const container = React.createElement("div", null, [Title, Button]);
const Container = () => (
<div>
<h3>total click :{counter}</h3>
<button onClick={countUp}>click me</button>
</div>
);
// ReactDOM.render(<Container />, root);
render();
</script>
</body>
</html>
<!-- <변경된 부분만 업데이트 되는게 좋은이유>
1. Vanilla JavaScript
Vanilla JavaScript에서는 DOM 변경을 직접 처리합니다. 즉, 필요한 DOM 요소를 직접 선택하고, 요소의 속성을 변경하거나 새로운 요소를 추가하거나 기존 요소를 제거하는 등의 작업을 직접 수행합니다.
DOM 변경이 발생하면, 브라우저는 변경된 DOM 트리를 다시 계산하고, 렌더 트리를 다시 생성한 후 화면에 그립니다. 이 과정은 비용이 많이 드는 연산으로, 자주 발생하게 되면 성능을 저하시킬 수 있습니다.
2. ReactJS
ReactJS는 DOM 변경을 처리하기 위해 가상 DOM(Virtual DOM)이라는 개념을 도입합니다. ReactJS에서는 먼저 메모리에 가상 DOM 트리를 생성합니다. 이 트리는 실제 DOM 트리의 사본으로서, 실제 DOM 트리와 별도로 존재합니다.
ReactJS는 상태 변경이 발생할 때마다 새로운 가상 DOM 트리를 생성하고, 이전의 가상 DOM 트리와 비교하여 변경된 부분을 파악합니다. 이렇게 파악된 변경 사항만 실제 DOM에 반영하는 방식을 사용합니다. 이 과정을 '재조정(Reconciliation)' 또는 'Diffing'이라고 부릅니다.
가상 DOM을 사용함으로써, 변경이 필요한 최소한의 요소만 실제 DOM에 반영되기 때문에 불필요한 연산을 줄이고 성능을 향상시킬 수 있습니다.
따라서, ReactJS는 복잡한 UI 업데이트를 효과적으로 처리할 수 있으며, 이를 통해 웹의 응답성을 향상시키고 사용자 경험을 개선할 수 있습니다
추가로 일반 자바스크립트를 쓴 브라우저는 노드정보가 바뀔때마다 노드트리를 처음부터 다시 생성한다 5단계에 걸쳐서. 근데 리액트는 가상돔을 써서 우리 시야에 보이는 부분만 수정해서 보여주고 모든 업뎃이 끝나면 일괄로 합쳐서 실제 돔에 던져준다 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>good example to state</title>
</head>
<!-- reactjs 내에서 데이터를 보관하고 자동으로 리렌더링 일으킬 수 있는 방법-->
<body>
<div id="root"></div>
<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");
//React.useState(0); 가 이전에 했던 countUp함수를 대신 해주는것(초기설정과 바뀌는 함수)
function App() {
const data = React.useState(0); //초기설정 가능
console.log(data); //[undefined ,f] undefined:data, f:data를 바꿀 함수
return (
<div>
<h3>total click :0</h3>
<button>click me</button>
</div>
);
}
ReactDOM.render(<App />, root);
</script>
</body>
</html>
<!--
구조 분해 할당 다음장 state04
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>good example to state2_구조분해 할당</title>
</head>
<!-- 구조분해 할당으로 데이터를 가져오기 const [counter, modifier] = React.useState(0);-->
<body>
<div id="root"></div>
<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");
//React.useState(0); 가 이전에 했던 countUp함수를 대신 해주는것(초기설정과 바뀌는 함수)
function App() {
// const data = React.useState(); //초기설정 가능
const [counter, modifier] = React.useState(0);
// console.log(data); //[undefined ,f] undefined:data, f:data를 바꿀 함수
return (
<div>
<h3>total click :{counter}</h3>
<button>click me</button>
</div>
);
}
ReactDOM.render(<App />, root);
</script>
</body>
</html>
<!--
const food = ["tomato","potato"] 이라는 배열이 있다 꺼내는방식2가지
원래는
const favtomato = food[0];이렇게 해야되는데
구조 분해 할당으로
const [myFavFood,mySecondFavFood] = food;
my FavFood //tomato
구조분해 할당이란?
열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>why we use modifier</title>
</head>
<body>
<div id="root"></div>
<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");
//React.useState(0); 가 이전에 했던 countUp함수를 대신 해주는것(초기설정과 바뀌는 함수)
function App() {
const [counter, setCounter] = React.useState(0);
const onClick = () => {
// counter = counter + 1;
// console.log(counter);
setCounter(counter + 1);
};
return (
<div>
<h3>total click :{counter}</h3>
<button onClick={onClick}>click me</button>
</div>
);
}
ReactDOM.render(<App />, root);
</script>
</body>
</html>
<!-- 새로 랜더 된걸로 다시 랜더 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>state를 설정하는 방법</title>
</head>
<!-- 현재값에서 바뀐 state값을 설정하는 방법
1. setCounter를 이용해서 바로 바꾸는 방법 / setCounter(12345);
2. 이전값을 이용해서 현재값을 계산하는 방법 setCounter((current)=>current+1);
-->
<body>
<div id="root"></div>
<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");
//사용자들이 input을 어떻게 얻는지와 form을 만들었을때 state는 어떤식으로 작용하는지
function App() {
const [counter, setCounter] = React.useState(0);
const onClick = () => {
//setCounter(counter+1);//확실히 현재값인지 모른다 어디서 바뀔지 몰라서
setCounter((current) => current + 1);
};
return (
<div>
<h3>total click :{counter}</h3>
<button onClick={onClick}>click me</button>
</div>
);
}
ReactDOM.render(<App />, root);
</script>
</body>
</html>
<!--
current로 해야 안전한 이유
setState() 즉각적인 명령이 아니라 컴포넌트를 갱신하라고 요청.
setState()는 컴포넌트를 항상 즉각적으로 갱신하지 않음. 오히려 여러 변경 사항과 함께 일괄적으로 갱신하거나, 나중으로 미룰 수 있음. 이로 인하여 setState()를 호출하자마자 this.state에 접근하는 것은 잠재적인 문제가 될 수 있음.
이전 state값을 기준으로 state값을 설정해야 한다면 setState((state)=> state+1)을 사용하는 것이 안전함
(공식문서참고, https://ko.reactjs.org/docs/react-component.html#setstate)
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>unit convert2</title>
</head>
<!-- 실제로 변환기 만들기 -->
<!-- 단위 변환 앱 분=> 시간 , 시간 => 분 -->
<body>
<div id="root"></div>
<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">
function App() {
const [amount, setAmount] = React.useState(0);
const [flipped, setFlipped] = React.useState(false);
const onChange = (event) => {
setAmount(event.target.value);
};
const reset = () => setAmount(0);
// const onFlip = () => setFlipped(!flipped);
const onFlip = () => {
reset();
setFlipped((current) => !current);
};
return (
<div>
<h1>super Converter</h1>
<div>
<label htmlFor="minutes">Minutes</label>
<input
value={flipped ? amount * 60 : amount}
type="number"
placeholder="Minutes"
id="minutes"
onChange={onChange}
disabled={flipped}
/>
</div>
<div>
<label htmlFor="hours">Hours</label>
<input
value={flipped ? amount : Math.round(amount / 60)}
type="number"
placeholder="hours"
id="hours"
disabled={!flipped}
onChange={onChange}
/>
<button onClick={reset}>Reset</button>
<button onClick={onFlip}>Flip</button>
</div>
</div>
);
}
const root = document.getElementById("root");
ReactDOM.render(<App />, root);
</script>
</body>
</html>
Properties 의 약어
- 부모 컴포넌트로부터 자식 컴포넌트에 데이터를 보낼 수 있게 하는 방법
- 자식의 인자에 부모 컴포넌트의 데이터를 전달한다.
- 자식은 부모의 데이터를 {props. 부모가 지정한 key}를 통해 사용할 수 있다.
- 또한, 바로 사용하는 방법(프로퍼티를 오브젝트에서 꺼내는 방법)으로 인자에 props대신 바로 {부모가 지정한 key}를 적어줘도 된다.
function btn(props){
return(
<div>
{props.sein}
</div>
)
}; //자식
function app(){
return(
<div>
<btn sein= "this into props"/>
//btn({sein:"this into props"})이렇게 들어간다 생각하면 됨
</div>
)//부모
};
---------------------바로 사용하는 방법🔽------------------
function btn({sein}){
return(
<div>
{sein}
</div>
)
}; //자식
function app(){
return(
<div>
<btn sein= "this into props"/>
//btn({sein:"this into props"})이렇게 들어간다 생각하면 됨
</div>
)//부모
};
💡 **알아 둘것**
📌React Memo(불필요한 렌더링 막기)
props가 변경되지 않는 한에서 렌더가 되지 않도록 막을 수 있다
const 변수 =React.memo();
컴포넌트가 React.memo()로 wrapping 될 때, React는 컴포넌트를 렌더링하고 결과를 메모이징(Memoizing)한다. 그리고 다음 렌더링이 일어날 때 props가 같다면, React는 메모이징(Memoizing)된 내용을 재사용한다.
📌PropTypes 모듈
npm i prop-types ⇒ import PropTypes from ‘prop-types’;
리액트는 파라미터를 잘 못 넘겨도 확인할 수 없는 문제점이 존재한다.
이런 문제를 줄이기 위해서 PropTypes라는 모듈의 도움을 받을 수 있다.
type과 다르게 입력 되었을 경우 warning을 뜨게 할수 있고, parameter 에 값을 넣지 않는 경우 경고 메시지를 띄울수 있다.
import PropTypes from "prop-types";
function Button({ text }) {
return <button>{text}</button>;
}
Button.propTypes = {
text: PropTypes.string.isRequired,
};
export default Button;
📌 CSS도 모듈화를 할 수 있다.
//css
.btn {
color: white;
background-color: tomato;
}
//Button.js 컴포넌트
import PropTypes from "prop-types";
import styles from "./Button.module.css";
function Button({ text }) {
return <button className={styles.btn}>{text}</button>;
}
Button.propTypes = {
text: PropTypes.string.isRequired,
};
export default Button;
import { useState, useEffect } from "react";
function App() {
const [counter, setValue] = useState(0);
const onClick = () => setValue((prev) => prev + 1);
console.log("i run all the time");//state될때 마다 실행
useEffect(() => {
console.log("CALL THE API....");// 첫 렌더 시점 한번만 실행
}, []);
return (
<div>
<h1>{counter}</h1>
----- keyword가 변화할때만 출력되는 코드(특정 시점에서만 렌더) -------
function App() {
const [counter, setValue] = useState(0);
const [keyword, setKeyword] = useState("");
const onClick = () => setValue((prev) => prev + 1);
console.log("i run all the time");
const onChange = (event) => setKeyword(event.target.value);
useEffect(() => {
console.log("I run only once.");
}, []);
useEffect(() => {
// 이렇게 디펜던시가 들어가 있으면 초기 값을 잘 봐야지 에러를 잡을 수 있다.
// 은근히 꽤나 자주 겪는 에러임 개 빡침
console.log("I run when 'keyword' changes.");
}, [keyword,a,b]); //keyword가 실행될때만 코드가 실행됨
📌Cleanup function (함수형 라이프 사이클에도 간단한 설명이 되어있음 참고)
function Hello() {
useEffect(function () {
console.log("hi :)");//실행될때
return function () {
console.log("bye :(");}; //실행되고 끝 (return문)
}, []);
📌map()
[‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’].map(() => “세인”)
//[‘세인’, ‘세인’, ‘세인’, ‘세인’, ‘세인’ ‘세인’] 인 새 배열을 만들어줌
['sein','hi','hello'].map((item) => item.toUpperCase())
//['SEIN','HI','HELLO']로 하면 item이 대문자로 바뀐 새로운 배열은 만들어줌
📌fetch() 와 async await
useEffect(() => {
fetch(
`https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year`
)
.then((response) => response.json())
.then((json) => {
setMovies(json.data.movies);
setLoading(false);
});
}, []);
------
function App() {
const [loading, setLoading] = useState(true);
const [movies, setMovies] = useState([]);//빈 배열
const getMovies= 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(() => {
getMovies()
}, []);
📌컴포넌트를 분리하고 props로 값 전달하기
//movie.js
function Movie({ coverImg, title, summary, genres }) {//props로 값 전달
return (
<div>
<img src={coverImg} alt={title} />
<h2>{title}</h2>
<p>{summary}</p>
<ul>
{genres.map((g) => (
<li key={g}>{g}</li>
))}
</ul>
</div>
);
}
export default Movie;
//app.js
import { useState, useEffect } from "react";
import Movie from "./Movie";//import 해주기
return (
<div>
{loading ? (
<h1>loading....</h1>
) : (
<div>
{movies.map((movie) => (// props에서 값을 받아 화면에 출력
<Movie
key={movie.id}
coverImg={movie.medium_cover_image}
title={movie.title}
summary={movie.summary}
genres={movie.genres}
/>
))}
</div>
)}
</div>
);
}
export default App;
📌설치하기
npm i react-router-dom@5.3.0
으로 설치 → 이런거는 최신버전 확인해서 설치하는게 좋음 @x.x.x 이부분이 버전임import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
로 import시켜준다.<Router>
<Switch>
<Route path="/url/:id"> // <= 얘(:id)가 리액트 라우터의 훅 useParams에서 가져오는친구
<컴포넌트/>
</Route>
<Route path="/url">
<컴포넌트/>
</Route>
</Switch>
</Router>
📌Link 컴포넌트
import { Link } from "react-router-dom";
<Link to=”/”></Link>
를 사용한다.
import { Link } from "react-router-dom";
function Movie({ coverImg, title, summary, genres }) {
return (
<div>
<img src={coverImg} alt={title} />
<h2>{title}</h2>
<h2>
<Link to="/movie">{title}</Link>
</h2>
<p>{summary}</p>
<ul>
{genres.map((g) => (
<li key={g}>{g}</li>
))}
</ul>
</div>
);
}
📌useParams()
import { useParams } from "react-router-dom";
로 사용클래스형 컴포넌트: class로 정의하고 render() 함수에서 jsx 코드를 반환
import {Component} from 'react'
class App extends Component{
constroctor(props){
super(props);
this.state={
}
}
render(){
return()
}
export default App
**컴포넌트 라이프사이클**
- Mount : DOM이 생성된 후 웹 브라우저에 나타나는 것.
- Update : 컴포넌트에서 props가 바뀔 때, state가 바뀔 때, 부모 컴포넌트 리렌더링 때, this.forceUpdate로 강제 렌더링할 때
- Unmount : 마운트의 반대 과정. DOM에서 컴포넌트를 제거하는 과정
**render() 함수**
- 준비한 UI를 랜더링한다
- 이 메서드 내부에서 this.props, this.state에 접근 가능, 리액트 요소를 반환
- 이 메서드 내부에서는 이벤트 설정이 아닌 곳에서 setState를 사용하면 안된다.
- 브라우저의 DOM에 직접 접근하면 안 되고, DOM 정보를 가져오거나 state를 변화시키고 싶다면 componentDidMount 메서드에서 처리해야 한다.
props
- {this.props.변수}로 전달한다.
state
- 컴포넌트가 내부적으로 자신의 상태를 바꾸고, 관리하기 위해 사용한다.
- 초기값이 필요하다.
this.state={}
- state안에 들어가는 값은 props로 전달 받은 값이다
- state값을 변경하기 위해서는 이벤트 부분에 this.setState({})로 변경해 주면 자동으로 render가 된다.
import {Component} from 'react'
class App extends Component{
constroctor(props){
super(props);
this.state={ // 초기값
movieList:[
{name:'영화1',rating:"3.5"},
{name:'영화1',rating:"3.5"},
{name:'영화1',rating:"3.5"},
]
}
}
const concatedList = this.state.movieList.cocat(movieObj);
this.setState({movieList:concatedList});
render(){
return(
<div>
<InputComp addMovieInfo={this.addMovieInfo}/>
</div>
)
}
export default App
📌npm i gh-pages
<방법>
npm i gh-pages → npm run build
"homepage": "https://jungsein.github.io/NC_Basic_React.git”
를 추가해준다“deploy”: ”gh-pages -d build”
를 적어주고, “predeploy”:”npm run build”
를 적어준다.npm run deploy
를 실행 시킨다