출처: 엘리스 , https://ko.reactjs.org/docs
npx create-react-app@latest .
git remote add origin 깃주소
package.json에 homepages 추가
{
"name": "reacttest",
"version": "0.1.0",
"private": true,
"homepage": "https://mcprotein.github.io/react-review/",
~
npm run build
npx gh-pages -d build
이걸 한번에 해줄 방법
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"deploy": "npm run build && npx gh-pages -d build"
},
<Button variant="outlined" onClick={createHandler}>
여기다가 createHandler() 처럼 함수로 주면 웹열리자마자 실행됨 html의 onclick과 다름
리액트에서는 onClick에다가 무조건 함수를 준다.
동적으로 생성된 값은 key값을 부여해서 리액트가 추적하기 쉽게 한다.
클로저: 자기가 속한 함수의 지역변수에 접근할 수 있다.
mode의 값이 바뀌었을 때, App()가 다시 호출되고, 그 return 값이 웹페이지에 반영되게 하고 싶다.
배열 안에 있는 객체에 key값이 필요한 이유: https://react.vlpt.us/basic/11-render-array.html
import "./App.css";
import { useState } from "react";
import Button from "@mui/material/Button";
import ButtonGroup from "@mui/material/ButtonGroup";
function HeaderTag(props) {
return (
<header>
<h1>
<a
href="/"
onClick={(evt) => {
evt.preventDefault();
console.log(props);
props.onSelect();
console.log("evt", evt);
}}
>
Web
</a>
</h1>
</header>
);
}
function Nav(props) {
const list = props.data.map((e) => {
return (
<li key={e.id}>
<a
href={"/read/" + e.id}
onClick={(evt) => {
evt.preventDefault();
props.onSelect(e.id);
}}
>
{e.title}
</a>
</li>
);
});
return (
<nav>
<ol>{list}</ol>
</nav>
);
}
function Article(props) {
return (
<article>
<h2>{props.title}</h2>
{props.body}
</article>
);
}
function App() {
const [mode, setMode] = useState("WELCOME");
const [id, setId] = useState(null);
console.log(id);
const topics = [
{ id: 1, title: "html", body: "html is ..." },
{ id: 2, title: "css", body: "css is ..." },
];
function createHandler() {
alert("create!");
}
let content = null;
if (mode === "WELCOME") {
content = <Article title="welcome" body="Hello, WEB!"></Article>;
} else if (mode === "READ") {
const topic = topics.filter((e) => {
if (e.id === id) {
return true;
} else {
return false;
}
})[0];
content = <Article title={topic.title} body={topic.body}></Article>;
}
return (
<div>
<HeaderTag
onSelect={() => {
setMode("WELCOME");
}}
></HeaderTag>
<Nav
data={topics}
onSelect={(id) => {
setMode("READ");
setId(id);
console.log(mode);
}}
/>
{content}
<ButtonGroup
variant="contained"
aria-label="outlined primary button group"
>
<Button variant="outlined" onClick={createHandler}>
Create
</Button>
<Button variant="outlined" onClick={() => alert("Update!")}>
Update
</Button>
<Button variant="outlined">Delete</Button>
</ButtonGroup>
</div>
);
}
export default App;
function App() {
const [mode, setMode] = useState("WELCOME"); // hook 사용
const [id, setId] = useState(null);
console.log(id);
const topics = [ // topics 데이터
{ id: 1, title: "html", body: "html is ..." },
{ id: 2, title: "css", body: "css is ..." },
];
function createHandler() {
alert("create!");
}
let content = null; // 초기 content는 null
if (mode === "WELCOME") { // mode가 WELCOME일때
content = <Article title="welcome" body="Hello, WEB!"></Article>; // Article 컴포넌트에 이렇게 넘김
} else if (mode === "READ") { // mode가 READ일때
const topic = topics.filter((e) => { // topics에 map을 가해서 각각의 원소 id와 id값이 같으면 true, 다르면 false 반환
if (e.id === id) {
return true;
} else {
return false;
}
})[0];
content = <Article title={topic.title} body={topic.body}></Article>; // id값이 같은 원소의 title과 body만 Article 컴포넌트에 넘김
}
return (
<div>
<HeaderTag
onSelect={() => {
setMode("WELCOME"); // HeaderTag 누르면 Mode가 WELCOME으로 바뀜
}}
></HeaderTag>
<Nav
data={topics}
onSelect={(id) => {
setMode("READ"); // Nav 누르면 Mode가 READ로 바뀌고 id값을 받아 setId를 한다.
setId(id);
console.log(mode);
}}
/>
{content} // content는 Mode가 뭐냐에 따라 다른 행동을 한다.
<ButtonGroup
variant="contained"
aria-label="outlined primary button group"
>
<Button variant="outlined" onClick={createHandler}> // Create버튼 누르면 createHandler 함수 실행
Create
</Button>
<Button variant="outlined" onClick={() => alert("Update!")}> // 이름없는 함수
Update
</Button>
<Button variant="outlined">Delete</Button>
</ButtonGroup>
</div>
);
}
function Article(props) {
return (
<article>
<h2>{props.title}</h2>
{props.body}
</article>
);
}
function Nav(props) {
const list = props.data.map((e) => {
return (
<li key={e.id}>
<a
href={"/read/" + e.id} // data={topics}로 데이터를 보내서 props.data는 topics가 된다.
onClick={(evt) => {
evt.preventDefault();
props.onSelect(e.id); // 원래 onSelect는 id를 받는데, 여기는 e.id를 주고 있고, e.id가 넘어가서
// onSelect={(e.id) => {
// setMode("READ");
// setId(e.id);
//console.log(mode); 이게 된다
}}
}}
>
{e.title}
</a>
</li>
);
});
return (
<nav>
<ol>{list}</ol>
</nav>
);
}
Header()도 Nav()랑 같은데, Header()는 하나만 보여주고 Nav()는 topics에 있는 목록을 보여줘야해서 Header()는 id를 넘기지 않고 mode만 바꾼다.
mode는 state이므로, mode가 바뀌면 다시렌더링이 되어 App()에서 {content}가 재실행되어 목록이 바뀌게 된다.
버튼은 Material UI를 사용했다.
https://mui.com/
부트스트랩 같은데 디자인은 더 세련된거같다.
() => activeLasers()
onClick={() => activeLasers()} (O)
onClick={activeLasers} (O)
onClick={activeLasers()} (X)
간단한 카운터 앱
import React, { useState } from 'react';
function Example() {
// "count"라는 새 상태 변수를 선언합니다
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count => count + 1)}>
Click me
</button>
</div>
);
}
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// componentDidMount, componentDidUpdate와 같은 방식으로
useEffect(() => {
// 브라우저 API를 이용하여 문서 타이틀을 업데이트합니다.
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
조건부 실행
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // count가 바뀔 때만 effect를 재실행합니다.
반드시 최상위 레벨에서만 Hook을 호출해야 한다.
for문이나 if문 안에서 호출하면 안됨
// react 라이브러리에서 useState 불러오기
import React, {useState, useEffect} from 'react'
import "../index.css"
function Counter(){
// useState 함수 (초기값 0) 의 결과를 counter, setCounter 변수에 할당
const [counter, setCounter] = useState(0);
const increaseCounter = () => {
// counter 값을 1 늘리도록 코드 작성
setCounter(counter => counter+1);
}
const decreaseCounter = () => {
// counter 값을 1 줄이도록 코드 작성
setCounter(counter => counter -1);
}
// useEffect 함수를 사용하여 document.title 변경
// 화살표 함수를 인자로 가진 useEffect
useEffect( () => {
// 실행할 사이드 효과
document.title = `현재 카운터 숫자: ${counter}`
}, [counter]); // counter가 변경될때만 이펙트 실행
useEffect(() => {}, [counter, name]) // counter, name이 변경될때만 이펙트 실행
useEffect(() => {}, []) // 처음 렌더링만 실행, 이후 절대 실행 x => api 최초 통신때만 데이터 받고 그후로는 데이터안받을때 사용
// 처음 렌더링때 실행x, 이후에 어떤 특정 순간에만 실행
const [executeNow, setExecuteNow] = useState(false);
useEffect(() => {
if(executeNow) {
//do whatever you want
setExecuteNow(false);
}
}, [executeNow]);
return(
<div className="counter">
<h2> 카운터 </h2>
<div>{ counter }</div>
<button onClick={increaseCounter}>증가하기</button>
<button onClick={decreaseCounter}>감소하기</button>
</div>
);
}
export default Counter
더많은 내용들 => https://react-hooks-cheatsheet.com/usestate 참조