폴더 생성
npx create-react-app builtin-functions --template typescript
json-server라이브러리 사용하기
json 파일을 사용하여 간단한 시뮬레이션능 위한 REST API Mock server 구축할 수 있는 툴입니다
설치
npm install -g json-server
구동하기
터미널 - cmd 설정
json-server --watch data.json파일 경로 --port 3003
data.json 파일은 만들거임
실습
db폴더 생성
data.json
{
"subjects": [
{
"id": 1,
"title": "javascript"
},
{
"id": 2,
"title": "php"
},
{
"id": 3,
"title": "react"
},
{
"title": "mysql",
"id": 4
}
],
"functions": [
{
"id": 1,
"subjects": 1,
"name": "map()",
"type": "array",
"syntex": "배열변수.map(li=>li+1)",
"desc": "배열요소의 형태를 변경하여 새로운 배열로 리턴"
},
{
"id": 2,
"subjects": 1,
"name": "filter()",
"type": "array",
"syntex": "배열변수.filter(li=>li>1)",
"desc": "배열요소중 조건에 맞는 요소만 새로운 배열로 리턴"
},
{
"id": 3,
"subjects": 1,
"name": "replace()",
"type": "string",
"syntex": "배열변수.filter(li=>li>1)",
"desc": "배열요소중 조건에 맞는 요소만 새로운 배열로 리턴"
},
{
"id": 4,
"subjects": 1,
"name": "strlen()",
"type": "string",
"syntex": "strlen(문자열)",
"desc": "문자열 길이 리턴"
},
{
"id": 5,
"subjects": 2,
"name": "var_dump()",
"type": "모든타입",
"syntex": "var_dump(변수)",
"desc": "데이터의 값과 타입을 반환"
},
{
"id": 6,
"subjects": 2,
"name": "strtoupper()",
"type": "string",
"syntex": "strtoupper(변수)",
"desc": "대문자로 변경후 반환"
},
{
"id": 7,
"subjects": 3,
"name": "useState()",
"type": "훅함수",
"syntex": "const [state, setState] = useState",
"desc": "상태관리"
}
]
}
생성 후
터미널 - cmd 창에 입력 (서버 실행)
json-server --watch ./src/db/data.json --port 3003
서버 주소 2개가 보일거임(주소창에 입력해서 확인하자)
Resources
http://localhost:3003/subjects
http://localhost:3003/functions
이렇게 잘나온다면 잘 실행된다는거임!!!!
모듈 만들러 가장!!
customhook 폴더 생성
useAcync.ts
import { useEffect, useReducer } from "react";
//상태를 위한 타입 (db datajson 타입설정함)
export type SubjectdataType = {
id: number;
title: string;
}
export type ListdataType = { //(db datajson 타입설정)
"id":number,
"subjects": number,
"name": string,
"type": string,
"syntex": string,
"desc": string
}
//상태타입
export type funState = {
loading: boolean;
data: null | SubjectdataType[] | ListdataType[];
error: null | object;
}
//모든 액션을 위한 타입
type funAction = {type: "LOADING"}
| {type: 'SUCCESS'; data: SubjectdataType[] | ListdataType []}
| {type: 'ERROR'; error: any}
function reducer(state: funState, action:funAction){
switch(action.type){
case 'LOADING':
return {
loading: true,
data: null,
error: null
};
case 'SUCCESS':
return {
loading: false,
data: action.data,
error: null
};
case 'ERROR':
return {
loading: false,
data: null,
error: action.error
};
default:
return state
}
}
type fetch =()=> void;
const useAsync = (callback: any, deps=[]): [funState, fetch] => {
const [state, dispatch] = useReducer(reducer, {
loading: false,
data: null,
error: null
})
const fetchData = async () => {
dispatch({type: 'LOADING'});
try{
const data = await callback();
dispatch({type: "SUCCESS", data})
}
catch(e){
dispatch({type: 'ERROR', error: e})
}
}
useEffect(()=>{
fetchData();
}, deps)
return [state, fetchData]; //useAsync 사용하면 상태와 패체데이타를 리턴해줌
}
export default useAsync;
화면을 구현해줄 컴포넌트 만들자
그 전에 styled-components를 사용하려면 라이브러리 설치해야한다
터미널-cmd 서버 유지상태로 터미널 하나 더 생성하고 라이브러리 설치
타입스크립트에 지원이 안되서 @types/ 붙이고 설치해야한다
npm install @types/styled-components
components폴더 생성
Header.tsx
import React from 'react';
import styled from 'styled-components'
const HeaderWrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 30px;
`;
const HeaderUl = styled.ul`
display: flex;
align-items: center;
li{
list-style:none;
padding: 0 20px;
}
`
const Header = () => {
return (
<HeaderWrapper>
<h1></h1>
<HeaderUl>
<li>과목등록</li>
<li>내장함수등록</li>
<li>함수리스트</li>
</HeaderUl>
</HeaderWrapper>
);
};
export default Header;
src 폴더
App.tsx
Header 조립
import React, { useState } from 'react';
import './App.css';
import Header from './components/Header';
function App() {
return (
<div className="App">
<Header sitename="typescript"/>
</div>
);
}
export default App;
Header 에 sitename을 props으로 보냈음
Header.tsx
//props로 받아서 타입지정해줘야함
type HeaderProps = {
sitename: string;
}
const Header = ({sitename}: HeaderProps) => {
return (
<HeaderWrapper>
<h1>{sitename}</h1>
<HeaderUl>
<li>과목등록</li>
<li>내장함수등록</li>
<li >함수리스트</li>
</HeaderUl>
</HeaderWrapper>
);
};
http://localhost:3003/subjects 주소에 있는 data를 화면에 구현하자
components 폴더
Subjects.tsx
import React from 'react';
import styled from 'styled-components'
import useAsync, { SubjectdataType } from '../customhook/useAcync';
async function getData() {
try {
const response = await fetch(`http://localhost:3003/subjects`)
const data = await response.json(); //요청받고 제이슨데이터로 변환
return data;
}
catch(e){
return e;
}
}
const SubWrapper = styled.div`
display: flex;
justify-content: center;
div{
margin: 10px;
background: skyblue;
color: white;
padding: 10px 20px;
border-radius: 6px;
}
`
const Subjects = () => {
const [subject, fetchData] = useAsync(getData) //모듈로 보냄
const {loading, data, error} = subject;
if(loading) return <div>로딩중입니다.</div>
if(error) return <div>에러발생!!!</div>
if(!data) return <div>데이터 없음!!</div>
return (
<SubWrapper>
{(data as Array<SubjectdataType>).map(da=>
<div key={da.id}>{da.title}</div>)}
</SubWrapper>
);
};
export default Subjects;
FetchAPI 알아보기
2023.01.24 - [javascript/javascript 고급문법] - [javascript] Fetch API
[javascript] Fetch API
Fetch API 도 XMLHttpRequest와 비슷하게 서버로부터 데이터를 받아오고 전송하지만 가장 큰 차이점은 Fetch API는 Promise방식으로 구성되어있다 그리고!!!! XMLHttpRequest보다 훨~~~씬 더 간결하다!!!!!! 구문) f
uou413.tistory.com
App에 조립
import React, { useState } from 'react';
import './App.css';
import Header from './components/Header';
import Subjects from './components/Subjects';
function App() {
return (
<div className="App">
<Header sitename="typescript"/>
<Subjects />
</div>
);
}
export default App;
http://localhost:3003/functions주소에 있는 data를 화면에 구현하자
components 폴더
Lists.tsx
import React from 'react';
import styled from 'styled-components';
import useAsync, { ListdataType } from '../customhook/useAcync';
async function getData() {
try {
const response = await fetch('http://localhost:3003/functions')
const data = await response.json() //받아온걸 제이슨데이터로
return data;
}
catch(e){
console.log(e)
}
}
const ListWrapper = styled.div`
text-align: center;
h2{
padding: 50px;
font-size: 28px;
}
table {
width: 100%;
max-width: 1100px;
margin: 0 auto;
border-collapse: collapse;
th{
border-top: 3px solid #333;
border-bottom: 1px solid #ccc;
padding: 20px;
}
td {
padding: 20px;
border-bottom: 1px solid #ccc;
}
}
`
const Lists = () => {
const [funtions, fetchData] = useAsync(getData);
let {data, loading, error} = funtions;
if(loading) return <div>로딩중입니다...</div>
if(error) return <div>에러발생!!!!</div>
if(!data) return <div>데이터 없음</div>
return (
<ListWrapper>
<h2>주요 내장 함수</h2>
<table>
<tbody>
<tr>
<th>번호</th>
<th>함수명</th>
<th>데이터 타입</th>
<th>구문</th>
<th>설명</th>
</tr>
{(data as Array<ListdataType>).map(da=><tr>
<td>{da.id}</td>
<td>{da.name}</td>
<td>{da.type}</td>
<td>{da.syntex}</td>
<td>{da.desc}</td>
</tr>)}
</tbody>
</table>
</ListWrapper>
);
};
export default Lists;
App에 조립
import React, { useState } from 'react';
import './App.css';
import Header from './components/Header';
import Subjects from './components/Subjects';
import Lists from './components/Lists';
function App() {
return (
<div className="App">
<Header sitename="typescript"/>
<Subjects />
<Lists/>
</div>
);
}
export default App;
타이틀을 클릭했을 때 타이틀에 맞는 데이터들만 리스트에 나오게 해보자
subjects에 있는 id값과 subjects 넘버값이 일치해야 보고싶은 타이틀을 클릭했을때 타이틀에 해당하는 리스트가 나와야한다 change 이벤트를 사용하여 타이틀 클릭했을 때 id값 받아오고 그 id값을 list컴퍼넌트로 보내서 일치하는지 조건을 준다
App 에 상태관리와 change이벤트를 작성하고 subjects컨퍼넌트에 onchange을 보내고
상태는 Lists컴퍼넌트로 보낸다
App.tsx
import React, { useState } from 'react';
import './App.css';
import Header from './components/Header';
import Subjects from './components/Subjects';
import Lists from './components/Lists';
function App() {
const [subject, setSubject] = useState(0);
const onChange = (subject: number): void => {
setSubject(subject);
}
return (
<div className="App">
<Header sitename="typescript"/>
<Subjects onChange={onChange}/>
<Lists subject={subject}/>
</div>
);
}
export default App;
Subjects.tsx
//props로 받으면 타입 지정해줘야함 리턴값없으므로 void
type subJectProps = {
onChange: (subject: number) => void;
}
const Subjects = ({onChange}: subJectProps) => {
const [subject, fetchData] = useAsync(getData)
const {loading, data, error} = subject;
if(loading) return <div>로딩중입니다.</div>
if(error) return <div>에러발생!!!</div>
if(!data) return <div>데이터 없음!!</div>
return (
<SubWrapper>
{(data as Array<SubjectdataType>).map(da=>
<div key={da.id} onClick={()=>onChange(da.id)}>{da.title}</div>)}
</SubWrapper>
);
};
Lists.tsx
//props로 받아서 타입지정해줘야함 change이벤트로 받은 number값
type listProps = {
subject:number;
}
const Lists = ({subject}: listProps) => {
const [funtions, fetchData] = useAsync(getData);
let {data, loading, error} = funtions;
if(loading) return <div>로딩중입니다...</div>
if(error) return <div>에러발생!!!!</div>
if(!data) return <div>데이터 없음</div>
if(data) {
if(subject > 0) { //title의 id값과 일치하는지 확인
data = (data as Array<ListdataType>).filter(da => da.subjects === subject);
}
}
근데 타이틀을 클릭하다보니 전체 리스트를 못본다..... 우씨...
전체 리스트를 보려면 router 설치하고 app에 두 컴퍼넌트의 상태값이 일치하면 안되기 때문에 Header에 change이벤트를 보내고 함수리스트라는 목록을 클릭했을 때 두 컴퍼넌트가 가지고 있지 않는 0값으로 상태 업데이트!!! 화면은 router를 사용하여 처음 화면으로 이동하게 설정해준다. 흠... 설명이 이상할 수도
router 설치
타입스크립트에서 지원이 안되서 @types/ 적어줄것
npm install @types/react-router-dom
App.tsx
import React, { useState } from 'react';
import './App.css';
import Header from './components/Header';
import Subjects from './components/Subjects';
import Lists from './components/Lists';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
function App() {
const [subject, setSubject] = useState(0);
const onChange = (subject: number): void => {
setSubject(subject);
}
return (
<BrowserRouter>
<div className="App">
<Header sitename="typescript" onChange={onChange}/>
<Routes>
<Route path="/" element={<>
<Subjects onChange={onChange}/>
<Lists subject={subject}/>
</>}/>
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
Header.tsx
//props로 받아서 타입지정해줘야함
type HeaderProps = {
sitename: string;
onChange: (subject:number)=>void;
}
const Header = ({sitename, onChange}: HeaderProps) => {
return (
<HeaderWrapper>
<h1>{sitename}</h1>
<HeaderUl>
<li>과목등록</li>
<li>내장함수등록</li>
<li onClick={()=>onChange(0)}><Link to="/">함수리스트</Link></li>
</HeaderUl>
</HeaderWrapper>
);
};
여기까지 타이틀에 맞게 list 내용 보기 끝!!!!!

다음은 title 추가 해주는 화면을 만들자
components폴더
AddSubject.tsx
import React, {useState} from 'react';
const AddSubject = () => {
const [subject, setSubject] = useState("")
const onChange = (e: React.ChangeEvent<HTMLInputElement>)=> { //e: 타입
setSubject(e.target.value)
}
const submit = () => { //추가버튼 클릭시 서버 보냄
fetch('http://localhost:3003/subjects', {
method: "POST",
headers: {
"Content-type": "application/json",
},
body: JSON.stringify({title: subject})
}).then(res=>{
console.log(res)
if(res.ok){
//성공하면 data.json파일에 내용 추가되면서 화면에 나타남(새로고침 ㅎㅎ)
alert("과목이 추가되었습니다")
}
})
.catch(e=> console.log(e))
}
return (
<div>
<input type="text" name="subject" onChange={onChange}/>
<button onClick={submit}>추가</button>
</div>
);
};
export default AddSubject;
타이틀 내용 추가해주는 페이지로 이동시켜줘야함!!!!
App 에 조립!!!!
App.tsx
import React, { useState } from 'react';
import './App.css';
import Header from './components/Header';
import Subjects from './components/Subjects';
import Lists from './components/Lists';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import AddSubject from './components/AddSubject';
function App() {
const [subject, setSubject] = useState(0);
const onChange = (subject: number): void => {
setSubject(subject);
}
return (
<BrowserRouter>
<div className="App">
<Header sitename="typescript" onChange={onChange}/>
<Routes>
<Route path="/" element={<>
<Subjects onChange={onChange}/>
<Lists subject={subject}/>
</>}/>
<Route path="/addSubject" element={<AddSubject/>}/>
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
다음은 list 내용 추가 해주는 화면을 만들자
components폴더
AddFunctions.tsx
import React, { useState } from 'react';
const AddFunctions = () => {
const [subject, setSubject] = useState({ //초기값 설정
subjects: "",
name: "",
type: "",
syntex: "",
desc: ""
})
const onChange = (e:React.ChangeEvent<HTMLInputElement>) =>{ //e: 타입
const {name, value} = e.target
setSubject({
...subject,
[name]: name === "subjects" ? Number(value): value
//subjects 값에 number값만 들어가야해서 조건줌
})
}
const submit = (e:React.FormEvent<HTMLFormElement>) => { //e: 타입
e.preventDefault();
console.log(subject)
fetch('http://localhost:3003/functions',{
method: 'POST', // 담아서 전송 post는 body에만 담을수 있음
headers: {
"Content-type": "application/json" //헤더값중 content-type 정의
},
body: JSON.stringify(subject) //object 를 문자 형태로
}).then(res=>{
if(res.ok){
alert("등록되었습니다")
}
})
.catch(e=>console.log(e))
}
return (
<div>
<form onSubmit={submit}>
<p><input type="text" name="subjects" placeholder='과목을입력하세요(숫자)'
value={subject.subjects} onChange={onChange}/></p>
<p><input type="text" name="name" placeholder='함수입력'
value={subject.name} onChange={onChange}/></p>
<p><input type="text" name="type" placeholder='타입입력'
value={subject.type} onChange={onChange}/></p>
<p><input type="text" name="syntex" placeholder='구문입력'
value={subject.syntex} onChange={onChange}/></p>
<p><input type="text" name="desc" placeholder='설명입력'
value={subject.desc} onChange={onChange}/></p>
<p><button type='submit'>추가</button></p>
</form>
</div>
);
};
export default AddFunctions;
HTTP Method 알아보기
2023.01.23 - [javascript/javascript 고급문법] - [javascript] XMLHttpRequest
[javascript] XMLHttpRequest
● XMLHttpRequest(XHR) 서버와 통신을 하도록 하는 객체 1. 객체는 서버와 상호작용하기 위해 사용 2. 전체 페이지를 새로고침하지 않아도 URL을 통해 데이터를 전송하거나 받아 올수 있음 3. XML데이터
uou413.tistory.com
Link도 같이 걸어줘야한다
Header.tsx
import { Link } from 'react-router-dom'; //추가!!!!!
const Header = ({sitename, onChange}: HeaderProps) => {
return (
<HeaderWrapper>
<h1>{sitename}</h1>
<HeaderUl>
<li><Link to="/addSubject">과목등록</Link></li>
<li>내장함수등록</li>
<li onClick={()=>onChange(0)}><Link to="/">함수리스트</Link></li>
</HeaderUl>
</HeaderWrapper>
);
};
list 내용 추가해주는 페이지로 이동시켜줘야함!!!!
App 에 조립!!!!
App.tsx
import React, { useState } from 'react';
import './App.css';
import Header from './components/Header';
import Subjects from './components/Subjects';
import Lists from './components/Lists';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import AddSubject from './components/AddSubject';
import AddFunctions from './components/AddFunctions';
function App() {
const [subject, setSubject] = useState(0);
const onChange = (subject: number): void => {
setSubject(subject);
}
return (
<BrowserRouter>
<div className="App">
<Header sitename="typescript" onChange={onChange}/>
<Routes>
<Route path="/" element={<>
<Subjects onChange={onChange}/>
<Lists subject={subject}/>
</>}/>
<Route path="/addSubject" element={<AddSubject/>}/>
<Route path="/addfunctions" element={<AddFunctions/>}/>
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
Link도 같이 걸어줘야한다
Header.tsx
const Header = ({sitename, onChange}: HeaderProps) => {
return (
<HeaderWrapper>
<h1>{sitename}</h1>
<HeaderUl>
<li><Link to="/addSubject">과목등록</Link></li>
<li><Link to="/addfunctions">내장함수등록</Link></li>
<li onClick={()=>onChange(0)}><Link to="/">함수리스트</Link></li>
</HeaderUl>
</HeaderWrapper>
);
};
끝!!!!!!!!!!!!!!끄끄ㅡ끄ㅡ끄끄끄끄끝!!!!!!!

'typescript' 카테고리의 다른 글
[typescript] typesafe-actions 라이브러리 (1) | 2023.02.24 |
---|---|
[typescript]react-typescript(redux) (0) | 2023.02.24 |
[typescript] as & ReturnType (0) | 2023.02.24 |
[typescript] react-typscript(useReducer + contextAPI) (0) | 2023.02.24 |
[typescript] react-typscript(usereducer) (0) | 2023.02.24 |
댓글