아파치 서버 추가 방법 :
import logo from './logo.svg';
import './App.css';
import React, { useState } from 'react'; // useState 훅 이용 (react에서 제공하는 기본적인 함수)
import customAxios from './customAxios';
import {
BrowserRouter as Router,
Routes,
Route,
Link
} from 'react-router-dom';
function Header(props){
console.log("props : " , props, props.title)
return <header>
<h1><a href='/' onClick={(event)=>{
event.preventDefault(); // 리로드 방지
props.onChangeMode(); // Header 태그에 작성한 이벤트 호출
}}>{props.title}</a></h1>
</header>
}
function Nav(props){
const lis = []
for(let i=0; i<props.topics.length; i++){
let t = props.topics[i];
lis.push(<li key={t.id}>
<a id={t.id} href={'/read/'+t.id} onClick={event=>{
event.preventDefault(); // 리로드 방지
props.onChangeMode(Number(event.target.id)); // Nav 태그에 작성한 이벤트 호출, event.target.id는 문자열
// event.target : 이벤트를 유발시킨 태그 = a 태그
}}>{t.title}</a>
</li>)
}
return <nav>
<ol>
{lis}
</ol>
</nav>
}
function Article(props){
return <article>
<h2>{props.title}</h2>
{props.body}
</article>
}
function Create(props){
return <article>
<h2>Create</h2>
<form onSubmit={event=>{
event.preventDefault(); // submit 됐을 때 reload 방지
const title = event.target.title.value; // event.target == form 태그
const body = event.target.body.value; // event.target == form 태그
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"/></p>
</form>
</article>
}
function Update(props){
const [title, setTitle] = useState(props.title); // props.title을 state로 환승
const [body, setBody] = useState(props.body); // props.body를 state로 환승
return <article>
<h2>Update</h2>
<form onSubmit={event=>{
event.preventDefault(); // submit 됐을 때 reload 방지
const title = event.target.title.value; // event.target == form 태그
const body = event.target.body.value; // event.target == form 태그
props.onUpdate(title, body);
}}>
<p><input type="text" name="title" placeholder="title" value={title} onChange={event=>{
setTitle(event.target.value);
}}/></p>
<p><textarea name="body" placeholder="body" value={body} onChange={event=>{
setBody(event.target.value);
}}></textarea></p>
<p><input type="submit" value="Update"/></p>
</form>
</article>
}
function App() {
// IP주소 변수 선언
const [ip, setIp] = useState('');
// IP주소 값을 설정합니다.
function callback(data) {
setIp(data);
}
// 첫번째 렌더링을 다 마친 후 실행합니다.
useState(
() => {
// 클라이언트의 IP주소를 알아내는 백엔드의 함수를 호출합니다.
customAxios('/ip', callback);
}, []
);
// const _mode = useState('WELCOME'); // 지역변수를 state로 업그레이드. 초기값: WELCOME
// const mode = _mode[0]; // state의 초기 값
// const setMode = _mode[1]; // state를 바꿀 때 사용
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="Hello, WEB"></Article>
} else if(mode === "READ"){
let title, 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={()=>{
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] // topics 배열 복제
newTopics.push(newTopic); // 복제본 변경
setTopics(newTopics); // 컴포넌트 다시 실행
setMode('READ');
setId(nextId);
setNextId(nextId+1);
}}></Create>
} else if(mode === 'UPDATE'){
let title, 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)=>{
const newTopics = [...topics] // topics 배열 복제
const updatedTopic = {id:id ,title:title, body:body} // mode === "READ" 가 실행된 상태이므로 id값은 id state를 사용해주면됨
for(let i=0; i<newTopics.length; i++){
if(newTopics[i].id === id){
newTopics[i] = updatedTopic;
break;
}
}
setTopics(newTopics);
setMode('READ');
}}></Update>
}
return (
<div>
<Router>
<div className="App">
<nav>
<ul>
<li>
<Link to="/">홈</Link>
</li>
<li>
<Link to="/about">소개</Link>
</li>
<li>
<Link to="/users">사용자</Link>
</li>
</ul>
</nav>
{/* <Routes>는 하위 <Route>들을 살펴보고 현재 URL과 일치하는 첫 번째 경로를 렌더링합니다. */}
<Routes>
<Route path="/about">
<About />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/">
<Home />
</Route>
</Routes>
</div>
</Router>
<Header title="WEB" onChangeMode={()=>{
setMode('WELCOME'); // state인 mode 값 변경
}}></Header>
<Nav topics = {topics} onChangeMode={(_id)=>{
setMode('READ'); // state인 mode 값 변경
setId(_id); // state인 id 값 변경
}}></Nav>
{content}
<ul>
<li><a href='/create' onClick={event=>{
event.preventDefault();
setMode('CREATE');
}}>Create</a></li>
{contextControl}
</ul>
</div>
);
}
function Home() {
// IP주소 변수 선언
const [ip, setIp] = useState('');
// IP주소 값을 설정합니다.
function callback(data) {
setIp(data);
}
// 첫번째 렌더링을 다 마친 후 실행합니다.
useState(
() => {
// 클라이언트의 IP주소를 알아내는 백엔드의 함수를 호출합니다.
customAxios('/ip', callback);
}, []
);
return (
<header className="App-header">
이 기기의 IP주소는 {ip}입니다.
</header>
);
}
function About() {
return (
<div>
<hr />
<h2>소개 페이지</h2>
</div>
);
}
function Users() {
return (
<div>
<hr />
<h2>사용자 페이지</h2>
</div>
);
}
export default App;
최종 코드
import logo from './logo.svg';
import './App.css';
import React, { useState } from 'react'; // useState 훅 이용 (react에서 제공하는 기본적인 함수)
import customAxios from './customAxios';
import {
BrowserRouter as Router,
Routes,
Route,
Link
} from 'react-router-dom';
function Header(props){
console.log("props : " , props, props.title)
return <header>
<h1><a href='/' onClick={(event)=>{
event.preventDefault(); // 리로드 방지
props.onChangeMode(); // Header 태그에 작성한 이벤트 호출
}}>{props.title}</a></h1>
</header>
}
function Nav(props){
const lis = []
for(let i=0; i<props.topics.length; i++){
let t = props.topics[i];
lis.push(<li key={t.id}>
<a id={t.id} href={'/read/'+t.id} onClick={event=>{
event.preventDefault(); // 리로드 방지
props.onChangeMode(Number(event.target.id)); // Nav 태그에 작성한 이벤트 호출, event.target.id는 문자열
// event.target : 이벤트를 유발시킨 태그 = a 태그
}}>{t.title}</a>
</li>)
}
return <nav>
<ol>
{lis}
</ol>
</nav>
}
function Article(props){
return <article>
<h2>{props.title}</h2>
{props.body}
</article>
}
function Create(props){
return <article>
<h2>Create</h2>
<form onSubmit={event=>{
event.preventDefault(); // submit 됐을 때 reload 방지
const title = event.target.title.value; // event.target == form 태그
const body = event.target.body.value; // event.target == form 태그
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"/></p>
</form>
</article>
}
function Update(props){
const [title, setTitle] = useState(props.title); // props.title을 state로 환승
const [body, setBody] = useState(props.body); // props.body를 state로 환승
return <article>
<h2>Update</h2>
<form onSubmit={event=>{
event.preventDefault(); // submit 됐을 때 reload 방지
const title = event.target.title.value; // event.target == form 태그
const body = event.target.body.value; // event.target == form 태그
props.onUpdate(title, body);
}}>
<p><input type="text" name="title" placeholder="title" value={title} onChange={event=>{
setTitle(event.target.value);
}}/></p>
<p><textarea name="body" placeholder="body" value={body} onChange={event=>{
setBody(event.target.value);
}}></textarea></p>
<p><input type="submit" value="Update"/></p>
</form>
</article>
}
function App() {
// IP주소 변수 선언
const [ip, setIp] = useState('');
// IP주소 값을 설정합니다.
function callback(data) {
setIp(data);
}
// 첫번째 렌더링을 다 마친 후 실행합니다.
useState(
() => {
// 클라이언트의 IP주소를 알아내는 백엔드의 함수를 호출합니다.
customAxios('/ip', callback);
}, []
);
// const _mode = useState('WELCOME'); // 지역변수를 state로 업그레이드. 초기값: WELCOME
// const mode = _mode[0]; // state의 초기 값
// const setMode = _mode[1]; // state를 바꿀 때 사용
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="Hello, WEB"></Article>
} else if(mode === "READ"){
let title, 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={()=>{
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] // topics 배열 복제
newTopics.push(newTopic); // 복제본 변경
setTopics(newTopics); // 컴포넌트 다시 실행
setMode('READ');
setId(nextId);
setNextId(nextId+1);
}}></Create>
} else if(mode === 'UPDATE'){
let title, 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)=>{
const newTopics = [...topics] // topics 배열 복제
const updatedTopic = {id:id ,title:title, body:body} // mode === "READ" 가 실행된 상태이므로 id값은 id state를 사용해주면됨
for(let i=0; i<newTopics.length; i++){
if(newTopics[i].id === id){
newTopics[i] = updatedTopic;
break;
}
}
setTopics(newTopics);
setMode('READ');
}}></Update>
}
return (
<div>
<Router>
<div className="App">
<nav>
<ul>
<li>
<Link to="/">홈</Link>
</li>
<li>
<Link to="/about">소개</Link>
</li>
<li>
<Link to="/users">사용자</Link>
</li>
</ul>
</nav>
{/* <Routes>는 하위 <Route>들을 살펴보고 현재 URL과 일치하는 첫 번째 경로를 렌더링합니다. */}
<Routes>
<Route path="/about" element={ <About /> }>
</Route>
<Route path="/users" element={ <Users /> }>
</Route>
<Route path="/" element={ <Home /> }>
</Route>
</Routes>
</div>
</Router>
<Header title="WEB" onChangeMode={()=>{
setMode('WELCOME'); // state인 mode 값 변경
}}></Header>
<Nav topics = {topics} onChangeMode={(_id)=>{
setMode('READ'); // state인 mode 값 변경
setId(_id); // state인 id 값 변경
}}></Nav>
{content}
<ul>
<li><a href='/create' onClick={event=>{
event.preventDefault();
setMode('CREATE');
}}>Create</a></li>
{contextControl}
</ul>
</div>
);
}
function Home() {
// IP주소 변수 선언
const [ip, setIp] = useState('');
// IP주소 값을 설정합니다.
function callback(data) {
setIp(data);
}
// 첫번째 렌더링을 다 마친 후 실행합니다.
useState(
() => {
// 클라이언트의 IP주소를 알아내는 백엔드의 함수를 호출합니다.
customAxios('/ip', callback);
}, []
);
return (
<header className="App-header">
이 기기의 IP주소는 {ip}입니다.
</header>
);
}
function About() {
return (
<div>
<hr />
<h2>소개 페이지</h2>
</div>
);
}
function Users() {
return (
<div>
<hr />
<h2>사용자 페이지</h2>
</div>
);
}
export default App;