npx create-react-app .
입력수정
npm start
입력 시, src/index.js를 찾고 이 파일을 동작하면서 react-app이 실행된다.import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
<App />
은 ./App로부터 비롯된다.import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
Helle, React!
</div>
);
}
export default App;
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
배포
npm run bulid
입력serve -s build
npx serve -s build
라고 입력하면 된다.const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
event.preventDefault()
props.onChangeMode()
<h1><a href="/" onClick={function(event) {
event.preventDefault();
props.onChangeMode();
}}>{props.title}</a></h1>
컴포넌트에서 입력은 props 였다. 이를 처리해서 어떤 값을 만드면 그것이 return 값이다.
이 때 props과 함께 컴포넌트 함수를 다시 실행해서 새로운 return 값을 만들어주는 것이 state이다.
useState의 인자는, 그 state의 초기값이다.
컴포넌트를 클릭하게 되면 setMode로 인해 function App이 다시 실행되고, mode 값, 즉 state가 바뀌게 된다.
props.onChangeMode(Number(event.target.id));
if (topics[i].id == id)
에서 제대로 숫자끼리 비교가 가능하여, 조건문 만족 시 우리가 원하는 코드를 동작하게 만들 수 있다.Update = Create + Read
props는 외부자가 내부자로 전달하는 값이다.
state는 내부자가 사용하는 값이다.
수정일 경우, function Update로 전달된 props의 title, body를 사용하는 것이 아니라, state로 변환 후 event가 발생할 때마다 setTitle, setBody로 title과 body가 변경되도록 해야 한다.
event.preventDefault()
를 해줄 필요가 없다.import logo from './logo.svg';
import './App.css';
import {useState} from 'react';
function Create(props) {
return <article>
<h2>Create</h2>
<form onSubmit={event=> {
event.preventDefault();
const title = event.target.title.value;
const body = event.target.body.value;
props.onCreate(title, body);
}}>
<p><input type="text" name="title" placeholder="title"/></p>
<p><textarea name="body" placeholder="body"></textarea></p>
<p><input type="submit" value="Create"></input></p>
</form>
</article>
}
function Update(props) {
const [title, setTitle] = useState(props.title);
const [body, setBody] = useState(props.body);
return <article>
<h2>Update</h2>
<form onSubmit={event=> {
event.preventDefault();
const title = event.target.title.value;
const body = event.target.body.value;
props.onUpdate(title, body);
}}>
<p><input type="text" name="title" placeholder="title" value={title} onChange={event=> {
// console.log(event.target.value);
setTitle(event.target.value);
}}/></p>
<p><textarea name="body" placeholder="body" value={body} onChange={event=> {
// console.log(event.target.value);
setBody(event.target.value);
}}></textarea></p>
<p><input type="submit" value="Update"></input></p>
</form>
</article>
}
function Header(props) {
return <header>
<h1><a href="/" onClick={(event) => {
event.preventDefault();
props.onChangeMode();
}}>{props.title}</a></h1>
</header>
}
function Nav(props) {
const list = []
for (let i = 0; i < props.topics.length; i++) {
let topic = props.topics[i];
list.push(<li key={topic.id}>
<a id={topic.id} href={'/read/' + topic.id} onClick={event=>{
event.preventDefault();
props.onChangeMode(Number(event.target.id));
}}>{topic.title}</a>
</li>)
}
return <nav>
<ol>
{list}
</ol>
</nav>
}
function Article(props) {
// console.log(props);
return <article>
<h2>{props.title}</h2>
{props.body}
</article>
}
function App() {
// const _mode = useState("WELCOME"); // 상태를 만드는 것이다. 그러면 상태가 리턴되어 _mode를 받을 것이다.
// useState는 배열을 반환한다. 그 배열의 0번째 원소는 '상태의 값'을 읽을 때 쓰는 데이터이고, 1번째 원소는 그 상태의 값을 변경할 때 쓰는 함수이다.
// const mode = _mode[0];
// const setMode = _mode[1];
// 위 3줄을 간단하게 아래처럼 1줄로 표현하기도 한다. 더 축약되어 있기 때문에 밑의 코드를 더 많이 쓴다.
const [mode, setMode] = useState("WELCOME");
const [id, setId] = useState(null);
const [nextId, setNextId] = useState(4);
const [topics, setTopics] = useState([
{id: 1, title: 'html', body: 'html is ...'},
{id: 2, title: 'css', body: 'css is ...'},
{id: 3, title: 'javascript', body: 'javascript is ...'}
]);
let content = null;
let contextControl = null;
if (mode === "WELCOME") {
content = <Article title="WELCOME" body="Welcome to React!"></Article>;
} else if (mode === "READ") {
let title = null;
let body = null;
for (let i = 0; i < topics.length; i++) {
if (topics[i].id == id) {
title = topics[i].title;
body = topics[i].body;
}
}
content = <Article title={title} body={body}></Article>;
contextControl = <>
<li><a href={"/update/" + id} onClick={event=> {
event.preventDefault();
setMode("UPDATE");
}}>Update</a></li>
<li><input type="button" value="Delete" onClick={(event)=> {
// event.preventDefault(); // button 타입의 input 태그는 기본 behavior가 없기 때문에 preventDefault()를 해주지 않아도 된다.
const newTopics = [];
for (let i = 0; i < topics.length; i++) {
if (topics[i].id != id) {
newTopics.push(topics[i]);
}
}
setTopics(newTopics);
setMode("WELCOME");
}}/></li>
</>
} else if (mode === "CREATE") {
content = <Create onCreate={(_title, _body)=> {
const newTopic = {id: nextId, title: _title, body: _body};
const newTopics = [...topics];
newTopics.push(newTopic);
setTopics(newTopics);
setMode("READ");
setId(nextId);
setNextId(nextId + 1);
}}></Create>
} else if (mode === "UPDATE") {
let title = null;
let body = null;
for (let i = 0; i < topics.length; i++) {
if (topics[i].id === id) {
title = topics[i].title;
body = topics[i].body;
}
}
content = <Update title={title} body={body} onUpdate={(title, body)=>{
// console.log(title, body);
const newTopics = [...topics];
const updatedTopic = {id: id, title: title, body: body};
for (let i = 0; i < newTopics.length; i++) {
if (newTopics[i].id === id) {
newTopics[i] = updatedTopic;
}
}
setTopics(newTopics);
setMode("READ");
}}></Update>;
}
return (
<div>
<Header title="WEB" onChangeMode={() => {
setMode("WELCOME");
}}></Header>
<Nav topics={topics} onChangeMode={(_id) => {
setMode("READ");
setId(_id);
}}></Nav>
{content}
<ul>
<li><a href="/create" onClick={event=> {
event.preventDefault();
setMode("CREATE");
}}>Create</a></li>
{contextControl}
</ul>
</div>
);
}
export default App;