React
프로젝트 생성
npx create-react-app react02
JSX
html 작성하듯이 작성하여 그대로 return 가능하도록한 문법 기존의 경우는 createElement를 해줘야하나 그러지 않아도 가능
단, 루트 element가 반드시 필요하기 때문에 p 태그같은것은 혼자 쓸 수 없다. 반드시 div 태그 든 <>(fragment)가 있어야만 한다.
태그는 반드시 닫아 주어야만 한다.
import "./App.css"; => .cl01{background-color: red};
function Ex01() {
// 자바스크립트의 변수를 담아 사용할 때는 {}를 이용하면 된다.
// let msg = 'Ex01 page';
// let color = {color: "red"};
// return <h1 style={color}>{msg} function을 이용한 엘리먼트</h1>
// root element가 반드시 존재해야한다.
// return <>
// <h1>제목</h1>
// <p>내용</p>
// </>
// className은 class를 준 것과 똑같이 사용된다.
return <>
<h1 className="cl01">제목</h1>
<p>내용</p>
</>
}
export default Ex01;
Component
컴포넌트를 생성할 때 반드시 첫글자를 대문자로 작성해야 한다. 그래야 기존의 태그보다 우선으로 인식된다.
클래스방식은 현재는 사용되지 않는다. 참고만.
props를 이용해서 값을 주고 받을 수 있다.
class H2 extends React.Component {
constructor(props){
super(props);
this.msg = props.msg2;
}
render() {
return <h1>H2 : {this.msg}</h1>
}
}
function Ex02(props) {
return (
<>
<h1 className="cl01">제목</h1>
<p>{props.msg}</p>
</>
)
}
function Ex01() {
return (
<>
<Ex02 msg="환영합니다.ddd"/>
<H2 msg2="클래스 방식"/>
</>
)
}
function Ex02({sub, msg}) {
return (
<>
<h1 className="cl01">{sub}</h1>
<p>{msg}</p>
</>
)
}
function Ex01() {
return (
<>
<Ex02 sub="한글" msg="환영합니다.ddd"/>
<Ex02 sub="eng" msg="wellcome"/>
<H2 msg2="클래스 방식"/>
</>
)
}
state
값만 바꾼다고해서 해당 DOM을 재수정 하진않기 때문에 이를 지정해주기 위해서 state를 사용한다.
기존의 msg의 값을 바꿔도 바로 적용되지않으며 반드시 setState를 해야만 DOM을 갱신한다.
class H2 extends React.Component {
constructor(props){
super(props);
this.msg = props.msg2;
this.state = {brand: "ford"};
}
render() {
return (
<>
<h1>H2 : {this.state.brand} {this.msg}</h1>
<button onClick={()=>{
this.msg = '바뀜';
const obj = this.state;
this.setState({...obj, brand: "수정"});
}}>입력</button>
</>
)
}
}
event
const Ex03 = ()=>{
const func01 = () => {
alert('클릭2');
};
return (
<div>
<button onClick={()=>{
alert('클릭');
}}>버튼</button>
<button onClick={func01}>클릭2</button>
<button onClick={func01}>클릭3</button>
</div>
)
};
if
function Goal(props) {
const isGoal = props.isGoal;
if (isGoal) {
return <MadeGoal/>;
}
return <MissedGoal/>;
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Goal isGoal={false} />);
&&
function Garage(props) {
const cars = props.cars;
return (
<>
<h1>Garage</h1>
{cars.length > 0 &&
<h2>
You have {cars.length} cars in your garage.
</h2>
}
{cars.length > 0 ? (
<h2>
You have {cars.length} cars in your garage.
</h2> )
: null
}
</>
);
}
const cars = ['Ford', 'BMW', 'Audi'];
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Garage cars={cars} />);
list - map
function Ex01() {
const cars = ['Ford', 'BMW', 'Audi'];
return (
<>
<ul>
{
cars.map((ele, idx)=><li key={idx}>{ele}</li>)
}
</ul>
</>
)
}
rfc - react functional component
새로운 컴포넌트를 만들 때 rfc 만 입력하고 자동완성하면 틀을 생성해준다.
import React from 'react'
export default function Ex02() {
return (
<div>Ex02</div>
)
}
useState
import React, { useState } from "react";
export default function Ex02() {
const [title, setTitle] = useState('제목없음');
const [ipval, setIpval] = useState(["",'']);
const func01 = (e) => {
e.preventDefault();
setTitle(e.target.ename.value);
}
const func02= (e) => {
if(e.target.name=='ename'){
setIpval([e.target.value, ipval[1]]);
} else if(e.target.name=='ename2'){
// setIpval([ipval[0], e.target.value]);
setIpval(ipval.map((ele,idx)=> idx==1 ? e.target.value : ele));
}
}
return (
<>
<div>
<h1>{title}</h1>
<input/>
<button onClick={() => {setTitle('제목있음')}}>클릭</button>
</div>
<form onSubmit={func01}>
<h1>{title}</h1>
<input name="ename" onChange={func02} value={ipval[0]}/>
<input name="ename2" onChange={func02} value={ipval[1]}/>
<button>전송</button>
</form>
</>
)
}
React-Router
npm react-router-dom
npm start
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import Ex01 from './Ex01';
import Ex02 from './Ex02';
import Ex03 from './Ex03';
import Nav from './Nav';
import reportWebVitals from './reportWebVitals';
import { Route, Routes, BrowserRouter} from 'react-router-dom';
// class My01 extends React.Component {
// render() {
// return <h1>환영합니다</h1>
// }
// }
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<Routes>
<Route path="/" element={<Nav />}>
<Route index element={<App />}/>
<Route path="p1" element={<Ex01 />}/>
<Route path="p2" element={<Ex02 />}/>
<Route path="p3" element={<Ex03 />}/>
</Route>
</Routes>
</BrowserRouter>
);
reportWebVitals();
Nav.js - Link 태그를 이용하면 SPA 처럼 됨
import React from 'react'
import { Link, Outlet } from 'react-router-dom'
export default function Nav() {
return (
<div>
<nav>
<Link to="/">home</Link>
<Link to="/p1">p1</Link>
<Link to="/p2">p2</Link>
<Link to="/p3">p3</Link>
</nav>
<Outlet/>
</div>
)
}
CRUD
Front - React
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import DeptList from './pages/DeptList'
import DeptAdd from './pages/DeptAdd'
import DeptDetail from './pages/DeptDetail'
import Nav from './Nav';
import reportWebVitals from './reportWebVitals';
import { Route, Routes, BrowserRouter} from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<Routes>
<Route path="/" element={<Nav />}>
<Route index element={<App />}/>
<Route path="list" element={<DeptList />}/>
<Route path="add" element={<DeptAdd />}/>
<Route path="detail" element={<DeptDetail />}/>
</Route>
</Routes>
</BrowserRouter>
);
reportWebVitals();
Components - Nav.js
import React from 'react'
import { Link, Outlet } from 'react-router-dom'
export default function Nav() {
return (
<div>
<nav className="navbar navbar-default">
<div className="container-fluid">
<div className="navbar-header">
<Link className="navbar-brand" to="/">
비트교육센터
</Link>
</div>
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul className="nav navbar-nav">
<li className="active"><Link to="/">home</Link></li>
<li><Link to="/list">list</Link></li>
<li><Link to="/add">add</Link></li>
<li><Link to="/detail">detail</Link></li>
</ul>
</div>
</div>
</nav>
<div className="container">
<Outlet/>
</div>
</div>
)
}
Components - DeptList.js
import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
export default function DeptList() {
const[list, setList] = useState([]);
useEffect(()=>{
fetch('http://localhost:8080/api/v1/dept')
.then((response)=> response.json())
.then((data) => setList(data));
// const dummy = [
// {deptno: 1111, dname: 'tester1', loc: 'test'},
// {deptno: 2222, dname: 'tester2', loc: 'test'},
// {deptno: 3333, dname: 'tester3', loc: 'test'},
// {deptno: 4444, dname: 'tester4', loc: 'test'}
// ];
// setList(dummy);
},[]);
return (
<>
<div>{list.length ?'': <span className='glyphicon glyphicon-refresh' aria-hidden="true"></span> }</div>
<div className="page-header">
<h1>list page<small>Subtext for header</small></h1>
</div>
<table className='table'>
<thead>
<tr>
<th>deptno</th>
<th>dname</th>
<th>loc</th>
</tr>
</thead>
<tbody>
{/* <tr>
<td><Link to="/detail">1111</Link></td>
<td><Link to="/detail">user1</Link></td>
<td><Link to="/detail">test</Link></td>
</tr> */}
{
list.map(ele => (
<tr key={ele.deptno}>
<td><Link to="/detail">{ele.deptno}</Link></td>
<td><Link to="/detail">{ele.dname}</Link></td>
<td><Link to="/detail">{ele.loc}</Link></td>
</tr>
))
}
</tbody>
</table>
</>
)
}
Back - boot
properties
Mysql 과 DB 연결
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.99.100:3306/mydb
spring.datasource.username=scott
spring.datasource.password=tiger
#logging.level.web=debug
logging.level.com.bit.boot03=debug
Vo
Lombok 라이브러리를 사용하여 Vo 정의
@Builder
@AllArgsConstructor
@Data
@NoArgsConstructor
public class DeptVo {
private int deptno;
private String dname, loc;
}
Controller
다소 무식한 방법이지만 일단 1차원적으로 메서드에 @CrossOrigin을 달아주면 CORS오류 해결
import ...;
@RestController
@RequestMapping("/api/v1/dept")
@AllArgsConstructor
public class DeptController {
private final DeptService deptService;
@CrossOrigin
@GetMapping
public List<?> getList(){
return deptService.selectAll();
}
}
Dao
Mybatis를 사용하기 때문에 Dao 인터페이스만 구현하여 Mapper 어노테이션 사용
import ...;
@Mapper
public interface DeptDao {
@Select("select * from dept")
List<DeptVo> findAll();
}
Service
@Slf4j
@Service
@AllArgsConstructor
public class DeptService {
private final SqlSessionFactory sqlSessionFactory;
public List<DeptVo> selectAll() {
log.debug("call");
return sqlSessionFactory.openSession().getMapper(DeptDao.class).findAll();
}
}
Boot03Application
@SpringBootApplication
@MapperScan(basePackageClasses = DeptDao.class)
public class Boot03Application {
@Autowired
DataSource dataSource;
public static void main(String[] args) {
SpringApplication.run(Boot03Application.class, args);
}
@Bean
public SqlSessionFactory getSqlSessionFactory() throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
}
'회고록(TIL&WIL)' 카테고리의 다른 글
TIL 2023.03.20 JPA, WebSocket (0) | 2023.03.20 |
---|---|
TIL 2023.03.17 React 2 (xhr, fetch, axios, CRUD, JPA) (0) | 2023.03.17 |
TIL 2023.03.15 Node.js 3 (Docker-network, Express-Generator, Express-session, JS-ES6, React) (0) | 2023.03.15 |
TIL 2023.03.14 Node.js 2 (express Project, nodemon, mongoDB) (0) | 2023.03.14 |
TIL 2023.03.13 Node.js (NVM, module, express, ejs, mysql) (0) | 2023.03.13 |