import logo from './logo.svg';
import './App.css';
import React, { useState } from 'react';
function Header(props) {
console.log('props', props)
return (
<header>
<h1><a href="/" onClick={(event)=>{
event.preventDedault();
props.onChangeMode();
}}>{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));
}}>{t.title}</a>
</li>);
}
return(
<nav>
<ol>
{lis}
</ol>
</nav>
);
}
function Article(props) {
return(
<header>
<article>
<h2>{props.title}</h2>
{props.body}
</article>
</header>
)
}
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=>{
setTitle(event.target.value);
}}></input></p>
<p><textarea name="body" placeholder="body" value={body} onChange={event=>{
setBody(event.target.value);
}}></textarea></p>
<p><input type="submit" value="Update"></input></p>
</form>
</article>
}
function App() {
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++){
console.log(topics[i].id, id);
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);
}}></input></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, 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;
break;
}
}
setTopics(newTopics);
}}></Update>
}
return (
<div className="App">
<Header title="React" onChangeMode={()=>{
setMode('WELCOME');
// alert('Header');
}}></Header>
<Nav topics={topics} onChangeMode={(id)=>{
setMode('READ');
setId(id);
// alert(id);
}}></Nav>
{content}
<ul>
<li><a href="/create" onClick={(event)=>{
event.preventDefault();
setMode('CREATE');
}}>Create</a></li>
{contextControl}
<li><a href="/update">Update</a></li>
</ul>
</div>
);
}
export default App;
npx create-react-app react-router-dom
react-router-dom-example>npm install react-router-dom
react-router-dom-example>npm list
react-router-dom-example> npm start
$ conda env list
$ conda create -n (가상환경이름)
$ conda activate (가상환경이름)
npm install react-router-dom
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
function App() {
return (
<BrowserRouter basename="/root">
<Routes>
<Route path="/intro" />
</Routes>
</BrowserRouter>
);
}
<Route path='*' element={<ErrorPage />} /> // ErrorPage 컴포넌트 필요
<Route path="*" element={<Navigate to="/" />} /> // Navigate 컴포넌트 이용
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/intro" /> <= "/root/intro"
<Route path="/product/foods" /> <= "/product/foods"
{ … }
</Routes>
</BrowserRouter>
);
}
function App() {
return (
<HashRouter>
<Routes>
<Route path="/intro" /> <= /#/about
<Route path="/faq" /> <= /#/faq
{ … }
</Routes>
</HashRouter>
);
}
라우터 컴포넌트 외에 기본적으로 제공되는 컴포넌트로 컴포넌트와 함께 사용되는 경우가 많다.
Routes
import { BrowserRouter, Routes, Route } from 'react-router-dom';
Route
import { BrowserRouter, Routes, Route } from 'react-router-dom';
path: 문자열. 매칭될 URL 경로를 지정한다.
element: URL에 매칭된 리액트 컴포넌트를 이용하여 리액트 요소를 생성한다.
Component: URL에 매칭을 이용하여 리액트 요소를 생성한다. RouterProvider를 이용하여 생성한다.
index: index 라우트로 지정되며 페이지가 없을 경우에도 기본으로 출력된다. 형제 라우트
들이 있을 경우 기본 라우트로 지정한다.
Link
import { Link } from 'react-router-dom';
to: 문자열. 이동할 URL 경로를 지정한다.
<ul>
<li><Link to="/">Home</Link></li>
<li><a href="/">Home</a></li>
</ul>
NavLink
import { NavLink } from 'react-router-dom';
style: CSS를 선언 한다.
className: 클래스 명을 지정한다.
to: 이동할 URL을 지정한다
// class명 이용
<NavLink to="/abut" className={
({isActive}) => isActive ? "activated" : "deacticated";
}>About</NavLink>
// Class 객체 이용
const activeStyle = { color: 'red' }
const deactiveStyle = { color: 'gray' }
<NavLink to="/abut" className={
({isActive}) => isActive ? activeStyle : deactiveStyle;
}>About</NavLink>
Navigate
import { Navigate } from 'react-router-dom';
replace: true 이면 이전 페이지로 이동할 수 없다.
state: useLocation 등에서 사용될 상태 객체를 전달한다.
to: 이동할 URL을 지정한다.
<Navigate to="/users" state={User} replace={true} />
Outlet
부모 컴포넌트에서 선언된 라우터를 자식 컴포넌트에서 사용할 경우 이용된다.
중첩된 라우트의 부모의 라우터를 자식 컴포넌트들에서 공통적으로 사용할 때 사용된다.
import { Outlet } from 'react-router-dom';
function App() {
return (
… <Link to="/"> HOME </Link>, Link to="/about"> ABOUT </Link>
<Routes>
<Route path="/" element={<Menu />}>
<Route path="home" element={<Home />} />
<Route path="about" element={<About />} />
</Route>
</Routes>
…
);
}
function Menu() {
return (
<div>
<h1>Menu</h1>
<Outlet />
</div>
);
}
path="/article/*"
/article
/article/1/2/3
/article/list/123
path="/:articleId?/list"
/1/list
/2/list
/list
path="/board/list/:boardId"
path="/board/:boardCode/list/:boardId"
path="/:articleId"
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
// import App from './App';
import reportWebVitals from './reportWebVitals';
import { HashRouter, Routes, Route, Link, NavLink } from 'react-router-dom';
ReactDOM.createRoot(document.getElementById('root')).render(
<HashRouter>
<App />
</HashRouter>
);
function Home() {
return (
<div>
<h2>Home</h2>
Home...
</div>
);
}
var contents = [
{id:1, title:'HTML', description:'HTML is...'},
{id:2, title:'JS', description:'JS is...'},
{id:3, title:'React', desctiption:'React is...'},
];
function Topic() {
return (
<div>
<h3>Topic</h3>
Topic...
</div>
);
}
function Topics() {
var lis = [];
for (var i=0; i<contents.length; i++) {
lis.push(
<li key={contents[i].id}>
<NavLink to={"/topics/" + contents[i].id}>{contents[i].title}</NavLink>
</li>
)
}
return (
<div>
<h2>Topics</h2>
<ul>
{lis}
</ul>
<Routes>
<Route path="/:topic_id" element={<Topic />} />
</Routes>
</div>
);
}
function Contact() {
return(
<div>
<h2>Contact</h2>
Contact...
</div>
);
}
function App() {
return (
<div>
<h1>Hello React Router DOM</h1>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/topics">Topics</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/topics/*" element={<Topics/>}/>
<Route path="/contact" element={<Contact/>}/>
<Route path="/*" element={'Not Found'}/>
</Routes>
<Home></Home>
<Topics></Topics>
<Contact></Contact>
</div>
);
}
// root.render(
// <BrowserRouter basename="/root">
// <Routes>
// <Route path="/intro" />
// </Routes>
// {/* <App /> */}
// </BrowserRouter>
// );
// 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();
index.css
.active{
background-color: tomato;
text-decoration: none;
}