
리엑트로 엘리먼트를 만드는게 가능한데 아래 방법은 공부할때만 하고 실전에서는 이렇게 쓰지 않는답니다.
공부는 니꼴라와 함께…
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
</body>
<script src="https://www.unpkg.com/react@18.3.1/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js"></script>
<script>
const root = document.getElementById("root");
const span = React.createElement("span", {style: {color: "red"}, id: "lol"}, "안녕하세여"); // 리엑트로 엘리먼트를 생성함
ReactDOM.render(span, root) // render : 사용자에게 보여준다 즉 html에 띄워준다?
</script>
</html>
React.createElement 의 인자를 알아보자
React.createElement("엘리먼트의 타입", {id: "클래스명, 아이디, 스타일 등"}, “텍스트”)
위 코드대로 하면 웹에선 이렇게 나온다


이런 식으로 body에 html 코드를 직접 작성하지 않고 스크립트로 띄워줄 수 있는데 이를 이용해서 그때 그때 사용자에게 보여주고 싶은 콘텐츠를 HTML이 업데이트 하게 해서 동적으로 보여줄 수 있을 것 같다.
이벤트 리스너를 이렇게 한 줄로 만들 수도 있다
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
</body>
<script src="https://www.unpkg.com/react@18.3.1/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js"></script>
<script>
const root = document.getElementById("root"); //HTML에서 id가 root인 블록을 가져옴
const h3 = React.createElement("h3", {
onMouseEnter: () => console.log("마우스 엔터") // 여기
}, "안녕하세여"); // 리엑트로 엘리먼트를 생성함
const btn = React.createElement(
"button",
{
onClick: () => console.log("눌렀다"), // 여기
style : {
backgroundColor: "tomato"
}
},
"나를 눌러요"
);
const container = React.createElement("div", null, [h3, btn]);// 두 원소를 한번에 출력하는 법
ReactDOM.render(container, root); // render : 사용자에게 보여준다 즉 html에 띄워준다?
</script>
</html>
React.createElement 는 너무 길다 더 간단하게 만들고 싶어!
JSX를 활용하면 crateElement를 대체해서 더 편하게 개발할수 있다.
JSX : JS를 확장한 문법
근데 JSX를 쓰려면 JSX를 브라우저가 알아먹을수 있는 형태로 바꿔주는 바벨(BABEL)이라는 녀석이 필요하다.
<!-- BABEL 임포트 -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
임포트 부분 말고 아래에 엘리먼트들을 만들어준 스크립트에도 타입을 지정해 주어야 바벨이 작동한다
<script type="text/babel">
const root = document.getElementById("root"); //HTML에서 id가 root인 블록을 가져옴
const Title =
<h3 id="title" onMouseEnter={() => console.log("마우스 엔터")}>
안녕하세여
</h3>
;
const Button = <button
style={{backgroundColor: "tomato"}}
onClick={() => console.log("눌렀다")}
>
나를 눌러요
</button>
const container = React.createElement("div", null, [Title, Button]);// 두 원소를 한번에 출력하는 법
ReactDOM.render(container, root); // render : 사용자에게 보여준다 즉 html에 띄워준다?
</script>
컴포넌트에 에로우 펑션 () => 을 붙여주면 변수처럼 쓸 수도 있다
대신 컴포넌트의 시작 문자는 대문자 여야 함
소문자로 하면 리엑트와 JSX는 이 컴포넌트를 HTML 태그라고 인식한다
<script type="text/babel">
const root = document.getElementById("root"); //HTML에서 id가 root인 블록을 가져옴
const Title = () =>
<h3 id="title" onMouseEnter={() => console.log("마우스 엔터")}>
안녕하세여
</h3>
;
const Button = () => <button
style={{backgroundColor: "tomato"}}
onClick={() => console.log("눌렀다")}
>
나를 눌러요
</button>
const Container = <div><Title /> <Button /></div>;// 번수처럼 쓰기!
ReactDOM.render(Container, root); // render : 사용자에게 보여준다 즉 html에 띄워준다?
</script>
F12를 눌러 브라우저에 표시된 코드를 봐보자
<script>"use strict";
var root = document.getElementById("root"); //HTML에서 id가 root인 블록을 가져옴
var Title = function Title() {
return /*#__PURE__*/React.createElement("h3", {
id: "title",
onMouseEnter: function onMouseEnter() {
return console.log("마우스 엔터");
}
}, "\uC548\uB155\uD558\uC138\uC5EC");
};
var Button = function Button() {
return /*#__PURE__*/React.createElement("button", {
style: {
backgroundColor: "tomato"
},
onClick: function onClick() {
return console.log("눌렀다");
}
}, "\uB098\uB97C \uB20C\uB7EC\uC694");
};
var Container = /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Title, null), /*#__PURE__*/React.createElement(Button, null)); // 두 원소를 한번에 출력하는 법
ReactDOM.render(Container, root); // render : 사용자에게 보여준다 즉 html에 띄워준다?
</script>
함수형식으로 콘솔 로그를 리턴하는 기존의 방식으로 번역된다.
const Button = () => <button
style={{backgroundColor: "tomato"}}
onClick={() => console.log("눌렀다")}
>
나를 눌러요
</button>
버튼을 클릭한 횟수를 출력하게 할건데 빨간약과 파란약이 있다.
안좋은 방법부터 해보자

<script type="text/babel">
const root = document.getElementById("root"); //HTML에서 id가 root인 블록을 가져옴
let counter = 0;
function countUp() {
counter += 1;
ReactDOM.render(<Container />, root);
// 랜더링을 또 해주지 않으면 변수값만 바뀌고 UI는 그대로임
}
const Container =() =>(
<div>
<h3>누른 횟수: {counter}</h3> // {}안에 변수를 넣어서 사용
<button onClick = {countUp}>나를 눌러요</button>
</div>);// 두 원소를 한번에 출력하는 법
ReactDOM.render(<Container />, root); // render : 사용자에게 보여준다 즉 html에 띄워준다?
</script>
<script type="text/babel">
const root = document.getElementById("root"); //HTML에서 id가 root인 블록을 가져옴
let counter = 0;
function countUp() {
counter += 1;
Render();
// 랜더링을 또 해주지 않으면 변수값만 바뀌고 UI는 그대로임
}
function Render() {
ReactDOM.render(<APP />, root);
}
function APP() {
return(
<div>
<h3>누른 횟수: {counter}</h3>
<button onClick={countUp}>나를 눌러요</button>
</div>// 두 원소를 한번에 출력하는 법
);
}
Render();
ReactDOM.render(<APP />, root);
</script>
둘다 같은 코드인데 이렇게 표현법이 다르다고 보여주고 싶어서 두개로 해봤다 난 북쪽이 더 좋다.
버튼을 누를때 마다 counter 를 1씩 더해주고 리렌더링을 해주는 방식인데
버튼을 누를 때 마다 렌더링을 계속하면 당연히 좋지 못할 것이다.
쌩 바닐라 JS로 하면 리렌더링을 하면 바뀌지 않은 값들도 다시 렌더링 하지만
리엑트에서는 변경된 놈들만 렌더링하기 때문에 매우 인터랙티브 한 웹을 개발할 수 있다.
(이걸 눈으로 보고싶으면 바닐라 버전과 리엑트 버전을 띄우고 크롬에서 F12를 누른후 버튼을 눌러보라)

이제 좋은 약을 먹어보자
<script type="text/babel">
const root = document.getElementById("root"); //HTML에서 id가 root인 블록을 가져옴
function APP() {
const [counter, setCounter] = React.useState(0); // useStates는 리턴값이 리스트인데 첫번째 원소는 변수의 값이고 두번째는 그 값을 변화시키는 함수이다
const onClick = () =>{
setCounter(counter + 1);
/*
counter += counter;
ReactDOM.render(<APP />, root);
//setCounter는 위 두줄을 한줄로 쓸수 있게 해준다
*/
}
return(
<div>
<h3>누른 횟수: {counter}</h3>
<button onClick = {onClick}>나를 눌러요</button>
</div>
);
}
ReactDOM.render(<APP />, root);
</script>
따로 함수 선언도 안하고 더 짧고 잘 보이고 쉽다!
일단 function APP 안에 counter랑 setCounter을 만들어 줄 거다.
React.useState 를 쓸건데 이게 뭐냐면
React.useState 의 반환값은 변수와 그 변수를 변화시키는 함수 가 리스트로 리턴된다.
반환값
[0, f]
그럼 위에선 React.useState가 어떻게 쓰였나
const [counter, setCounter] = React.useState(0);
[변수명, 함수명] (변수 초기화 값);
리스트가 할당연산자 앞에 오는 기괴한 문법이지만 매우 편리해 보이는 문법이다.
좋지아니한가
원곡인 크라잉넛도 좋은데 YdBB밴드도 맛있습니다. 서로 다른 맛이니 누가 더 좋니 마니 싸우지 마십쇼 -_-
북쪽 코드는 쌩 바닐라로 만든 클릭 횟수 출력이고 아래는 리엑트 버전이다.
<!DOCTYPE html>
<html>
<body>
<span>누른 횟수: 0</span>
<br>
<button id = "btn">Click me</button>
</body>
<script>
let counter = 0;
const button = document.getElementById("btn");
const span = document.querySelector("span");
function handleClick() {
counter += 1;
span.innerText = `누른 횟수: ${counter}`;
}
button.addEventListener("click", handleClick);
</script>
</html>
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
</body>
<script src="https://www.unpkg.com/react@18.3.1/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18.3.1/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 [counter, setCounter] = React.useState(0);
const onClick = () =>{
setCounter(counter + 1);
}
return(
<div>
<h3>누른 횟수: {counter}</h3>
<button onClick = {onClick}>나를 눌러요</button>
</div>
);
}
ReactDOM.render(<APP />, root);
</script>
</html>
임포트 부분을 빼면 길이 자체는 비슷해 보이지만 리엑트를 쓰는 편이 역시 함수나 변수를 덜 선언하고 만들 수 있어서 효율이 좋고 차후 인터랙티브한 웹을 구현할 때 변경된 부분만 렌더링을 할 수 있어 더 적합하다.
근데 또 더 안전한 방법이 있다
<script type="text/babel">
const root = document.getElementById("root");
function APP() {
const [counter, setCounter] = React.useState(0);
const onClick = () =>{
// setCounter(counter + 1);
setCounter((current)=> current+1)// 여기를 잘 보시라
}
return(
<div>
<h3>누른 횟수: {counter}</h3>
<button onClick = {onClick}>나를 눌러요</button>
</div>
);
}
ReactDOM.render(<APP />, root);
</script>
setCounter(counter + 1); 이거는 counter 값이 현재 counter 의 값이라는 보장이없다.
거의 없겠지만 다른데서 이 변수를 건들거나 뭔가 업데이트가 되어서(비동기 등)업데이트 전의 값이나 잘못된 값이 전달되어 버그가 날 수도 있다.
setCounter((current)=> current+1)
current 는 React가 자동 현재 상태 값을 넘겨주는 기능이라 현재 counter 의 값을 확실하게 넘겨줄 수 있다.
JSX에서 주의해야 할 점이 있다
<script type="text/babel">
const root = document.getElementById("root");
function APP() {
return (
<div>
<h1 className="hi">짱좋은 변환기</h1>
<label htmlFor="minutes">Minutes</label>
<input id = "minutes" placeholder="Minutes" type="number" />
<label htmlFor="hours">Hours</label>
<input id ="hours" placeholder="Hours" type="number" />
</div>
);
}
ReactDOM.render(<APP />, root);
</script>
html속성 과 JSX의 예약어가 겹친다는 것인데
class 는 className
for 는 htmlFor
로 적어야한다.
JS에는 == 연산자와 ===연산자가 있습니다.
둘이 뭐가 다를까요~?

== 연산자는 두 값을 비교할 때, 타입을 자동으로 변환하여 비교합니다! 자료형이 달라도 값만 같으면 true를 반환하지요
=== 연산자는 타입 변환을 하지 않고 두 값을 비교합니다! 즉 자료형이 다르면 false를 반환합니다!
<script type="text/babel">
const root = document.getElementById("root");
function APP() {
const [amount, setAmount] = React.useState()
const [flipped, setFlipped] = React.useState(false);
const onChange = (event) => {
setAmount(event.target.value);
};
const reset = () => setAmount(0);
const onFlip = () => {
reset();
setFlipped((current) => !current);
}
return (
<div>
<div>
<h1 className="hi">분-시간 변환기</h1>
<label htmlFor="minutes">Minutes</label>
<input
value={flipped ? amount * 60 : amount}
id="minutes"
placeholder="Minutes"
type="number"
onChange={onChange}
disabled={flipped}
/>
</div>
<div>
<label htmlFor="hours">Hours</label>
<input
//value={minutes / 60}
value={flipped ? amount : Math.round(amount / 60)}
id="hours"
placeholder="Hours"
type="number"
disabled={!flipped}
onChange={onChange}
/>
</div>
<button onClick={reset}>Reset</button>
<button onClick={onFlip}>Flipped</button>
</div>
);
}
ReactDOM.render(<APP />, root);
</script>
<script type="text/babel">
function Btn(props) {
return <button style={{
backgroundColor: "tomato",
color: "white",
padding: "10px 20px",
border: 0,
borderRadius: "10px",
fontSize: props.big? 18: 16,
}}>
{props.text}
</button>
}
function APP() {
return (
<div>
<Btn text="저장" big={true} />
<Btn text="확인" big={false} />
</div>
);
}
const root = document.getElementById("root");
ReactDOM.render(<APP />, root);
</script>
Btn 컴포넌트를 이와 같이 재활용 할수있다
Btn 컴포넌트에 text와 big이라는 변수를 추가해서 버튼 컴포넌트를 커스텀 할 수도 있다.
그리고 여기에 다는 추가 사항들은 모두 props이지 이벤트 리스너를 만드는 것은 아니다
컴포넌트를 쓸때 넣어준 변수에 이렇게 접근할 수도 있다
function Btn({text, big}) {
return <button style={{
backgroundColor: "tomato",
color: "white",
padding: "10px 20px",
border: 0,
borderRadius: "10px",
fontSize: props.big? 18: 16,
}}>
{text}
</button>
}
<script type="text/babel">
function Btn({text, changeVal}) {
return <button
onClick={changeVal}
style={{
backgroundColor: "tomato",
color: "white",
padding: "10px 20px",
border: 0,
borderRadius: "10px",
}}>
{text}
</button>
}
function APP() {
const [val, setVal] = React.useState("Save Changes")
const changeVal = () => setVal("Revert Changes")
return (
<div>
<Btn text={val} changeVal={changeVal} />
<Btn text="확인" />
</div>
);
}
const root = document.getElementById("root");
ReactDOM.render(<APP />, root);
</script>
Prop Types 패키지를 쓰면 prop의 자료형이 잘못 쓰이고 있는지 알수있다
<script src="https://unpkg.com/prop-types@15.7.2/prop-types.js"></script>
이렇게 잘못된 값들을 넣어주면
Btn.propTypes ={
text: PropTypes.string,
fontSize: PropTypes.number,
}
function APP() {
return (
<div>
<Btn text="Save Changes" fontSize={18} />
<Btn text={14} fontSize={"Continue"} />
</div>
);
}

짜잔
이제 리엑트 를 진짜 설치해서 연습해 보자
콘솔에 아래 명령어를 입력하자
npx create-react-app Hwiflix

아,,, 이름에 대문자 금지란다
npx create-react-app hwiflix
이걸로 다시 하자…
다 깔리고 npm start 를 콘솔에 입력하면

시공의 폭풍같은 웹서버가 실행된다.
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"); // 렌더링 할때마다 실행
useEffect(() => {
console.log("Call the API");
}, []); //처음 한번만 렌더할 함수는 이곳에 넣어준다
return (
<div>
<h1>{counter}</h1>
<button onClick={onClick}>나를 눌러요</button>
</div>
);
}
export default App;
useEffect 를 활용하면 코드가 한번만 실행되게 할 수 있다. 더링이 일어나도 useEffect 에 있는 코드는 처음 렌더링 할 때 한번만 실행된다.
import { useState, useEffect } from "react";
function App() {
const [counter, setValue] = useState(0);
const [keyword, setKeyword] = useState("");
const onClick = () => setValue((prev) => prev + 1);
const onChange = (event) => setKeyword(event.target.value);
useEffect(() => {
console.log("Call the API");
}, []); //처음 한번만 렌더할 함수는 이곳에 넣어준다
useEffect(() => {
if (keyword !== "" && keyword.length > 6) {
console.log("SERACH", keyword);
}
}, [keyword]); // keyword가 바뀔때만 실행
return (
<div>
<input
value={keyword}
onChange={onChange}
type="text"
placeholder="Serch"/>
<h1>{counter}</h1>
<button onClick={onClick}>나를 눌러요</button>
</div>
);
}
export default App;
[ ]안에 데이터를 넣어주면 해당 데이터가 변화할 때 만 실행한다
import { useState, useEffect } from "react";
function Hello() {
useEffect(() => {
console.log("Created"); // Hello가 렌더링 될때만
return () => console.log("distroyed");// Hello가 제거될때만
}, []);
return <h1>Hello</h1>;
}
function App() {
const [showing, setShowing] = useState(false);
const onClick = () => setShowing((prev) => !prev);
return (
<div>
{showing ? <Hello /> : null}
<button onClick={onClick}>{showing ? "Hide" : "Show"}</button>
</div>
);
}
export default App;
useEffect로 불러와서 렌더링 됳 때와 다시 제거될 때 코드가 각각 실행되게도 할 수 있다.
function Hello() {
function DestroyedFn() {
console.log("Destroyed");
}
function CreatedFn() {
console.log("Created");
return DestroyedFn;
}
useEffect(CreatedFn, []);
return <h1>Hello</h1>;
}
이렇게 나눌 수 도 있는데 기능은 똑같다
아무튼 강의보고 프론트엔드만 만들었다.
https://techn-0.github.io/hwiflix_react/
이제 백엔드를 쓰는 게시판 형태의 웹서버도 만들어야 한다
개추~