87일차 내용 정리

채공부·2025년 9월 24일

Comments.jsx

  • 매개변수는 객체 하나
  • 구조 분해 할당 문법을 사용해 객체의 4개 속성
    (category, parentNum, parentWriter, list)을 각각 변수로 받아 사용

답글

  • Comment.jsx 에 handleReplyCountBtn 함수 추가
    • 대댓글 보기 버튼을 눌렀을 때 실행할 함수
const handleReplyCountBtn = (e) => {

};
  • 답글 버튼에 onClick 이벤트 추가
{ item.replyCount !== 0 && item.num === item.groupNum && 
	<button onClick={handleReplyCountBtn} className="dropdown-btn btn btn-outline-secondary btn-sm position-absolute"
		style={{bottom:"16px", right:"16px"}}>
		<i className="bi bi-caret-down"></i>
		답글 {item.replyCount}</button> 
}
  • handleReplyCountBtn 함수 안에 코드 추가
    • 버튼 아이콘 방향 토글 (▲, ▼)
    • 관련 대댓글 목록의 표시/숨김을 제어
// click 이벤트가 발생한 버튼의 참조값
const item = e.target;
//click 이벤트가 발생한 그 버튼의 자손요소 중에서 caret up 또는 caret down 요소를 찾는다
const caret = item.querySelector(".bi-caret-up, .bi-caret-down");
// caret 모양을 위 아래로 토글 시킨다 	
caret.classList.toggle("bi-caret-down");
caret.classList.toggle("bi-caret-up");

// 1. 버튼(item)의 두 단계 부모 요소로 이동
const grandParent = item.parentElement.parentElement;
// 2. 두단계 부모요소의 바로 다음 형제 요소의 참조값을 얻어낸다 
let next = grandParent.nextElementSibling;
// 3. 반복문 돌면서 (다음 형제 요소가 있는 동안에 반복문 돌기)
while (next) {
	//만일 re-re 클래스가 존재한다면 
  	if (next.classList.contains("re-re")) {
    	// d-none 클래스를 토글시켜서 보였다 숨겼다를 반복 시킨다
    	next.classList.toggle("d-none");
  	}else{//존재하지 않으면 
    	//반복문 탈출 
    	break;
  	}
  	//다음 형제 요소의 참조값 얻어내기  
  	next = next.nextElementSibling;
}

TypeScript

  1. react 폴더 안에서 cmd 실행

  2. react-typescript 생성

npm create vite react-typescript
  1. React 선택

  2. TypeScript 선택

  3. react-typescript 폴더로 이동

cd react-typescript
  1. 의존 dependency 설치
npm install
  1. VS CODE 에 react-typescript 로 폴더 workspace

  1. 서버 열기
npm run dev

  • eslint.config.js 에 코드 추가
rules: {
	'no-unused-vars': ['warn', { varsIgnorePattern: '^[A-Z_]' }],
},

type

App

  • App.tsx 에 테스트 코드 추가
function App() {
	return <>
    	<div>
      	<h1>Type Script 를 사용해 보자</h1>
    	</div>
  	</>
}
  • App.jsx 에 기본 type 을 익히기 위한 테스트 코드 추가
    • let 변수명 : type
    • const 변수명 : type

int age = 10;

let age : number = 10;

in java ➜ String name = "kimgura"

let name : string = "kimgura";

in java ➜ boolean isMan = true;

let isMan : boolean = true;
  • type 을 선언하지 않으면 type 을 추론 (infer) 해서 type 을 결정한다
let num1 = 10; // num1 은 number type 이다
let yourName = "park"; // yourName 은 string type 이다

  • 버튼 & 메세지 관련 useState 함수 추가
const [msg, setMsg] = useState("hi");
<button>{msg}</button>

  • 버튼에 onClick 이벤트 추가
<button onClick={() => setMsg("clicked")}>{msg}</button>

  • 데이터 관련 useState 함수 추가
    • useState() 를 사용할 때 type 을 명시할 수 있다
    • 처음에는 비워두었다가 추후 결정할 시 사용
const [data, setData] = useState<string>();

  • 숫자 관련 useState 함수 추가
const [num, setNum] = useState<number>();
  • nums, names 상수의 배열 type 선언
const nums : number[] = [10, 20, 30];
const names: string[] = ["kim", "lee", "park"];
  • 친구 관련 useState 함수 추가
    • 친구 이름 목록을 상태값으로 관리
const [friends, setFriends] = useState<string[]>(names);
  • object 을 담을 변수 m1 추가
let m1 = {num:1, name:"유재석", isMan:true};

  • m1 에 또 다른 object 를 담는다
m1 = {num:2, name:"박명수", isMan:false};
  • 에러 예시 코드
    • type 이 맞지 않는다면 에러가 발생
m1 = {myNum:3, myName:"정준하"};
  • 변수 m2 의 type 을 선언
let m2 : {num:number; name:string; isMan:boolean} = m1;
  • Member 객체 추가
    • object 의 type 을 미리 선언하고 재사용 할 수 있다
type Member = {
	num : number;
	name : string;
	isMan : boolean;
};
  • 미리 선언한 type 으로 m3 변수
let m3 : Member = {
	num : 3,
  	name : "정준하",
  	isMan : true
};
  • 미리 선언한 type 으로 배열을 만들 수도 있다
const members : Member[] = [m1, m2, m3];

App2

  • src 폴더 안에 App2.tsx 생성
function App2() {
    return <>
    
    </>
}
  • f1 함수 추가
    • f1 은 () => void 타입으로 추론된다
let f1 = () => {};

  • 함수 f2 추가
    • f2 의 type 을 명확히 선언
let f2 : () => void = () => {};
  • 함수 f3 추가
    • f3 는 (msg:string) => void 타입으로 추론된다
let f3 = (msg:string) => {};

  • 함수 f4 추가
    • f4 는 (msg:string) => number 타입으로 추론된다
let f4 = (msg:string) => {
	return msg.length;
};

➜ 해당 f4 함수는 JAVA 에서 이렇게 해석된다

public int f4(String msg){
	return msg.lenght();
}
  • f4 함수 호출 시 문자를 사용한다면?

➜ 에러 발생

  • 상수 result 추가
    • 함수의 type 이 명확하기 때문에 사용할 때 편리하다
const result:number = f4("hello");
  • Add 라는 함수 type 선언
type Add = (a:number, b:number) => number;
  • Add type 의 함수 getSum을 만들어서 대입해 보기
const getSum:Add = (num1:number, num2:number) => {
	return num1 + num2;
};

App3

  • src 폴더 안에 App3.tsx 생성
function App3() {
    return <>
    
    </>
}
  • src 폴더 안에 types 폴더를 생성 후 그 안에 type.ts 생성
    • 자주 사용하는 type 을 미리 정의하고 import해서 사용할 수 있다
export type MemberDto = {
    num : number;
    name : string;
    addr : string;
};

export type BoardDto = {
    num : number;
    writer : string;
    title : string;
};
  • App3.tsx 에 MemberDto type 객체에 회원 한 명의 정보 담아보기
const m1:MemberDto = {num:1, name:"유재석", addr:"압구정"};
  • BoardDto type 객체에 글 하나의 정보를 담아보기
const b1:BoardDto = {num:1, writer:"성해나", title:"혼모노"};
  • 모든 type 은 nullundefined 을 허용하지 않는다
const num1:number = null;
const myName:string = undefined;
  • null 또는 undefined 로 넣으려면 | null 또는 | undefined
    type 선언에 추가한다
const num2:number|null = null;
const myName2:string|undefined = undefined;
  • useState 함수 추가
const [state, setState] = useState<MemberDto>();

⚠️ 만일 state 초기값을 넣어주지 않는다면 undefined 로 추론된다

  • useState 에 초기값 전달
    • MemberDto 객체를 상태값으로 관리하려면 아래와 같은 모양으로 사용하면 된다
const [state, setState] = useState<MemberDto>({
	num : 0,
	name : "",
	addr : ""
});

App4

  • src 폴더 안에 App4.tsx 생성
function App4() {
    return <>
    
    </>
}
  • jsx 객체응 JSX.Element 타입으로 추론된다
import type { JSX } from "react";
const p1 = <p>p1 입니다</p>;
const p2:JSX.Element = <p>p2 입니다</p>;
  • list 는 JSX.Element[] 타입으로 추론된다
const list = [
  	<li>하나</li>,
  	<li>두울</li>,
 	 <li>세엣</li>
];
  • list2 의 type 을 명시
const list2:JSX.Element[] = [
  	<li>하나</li>,
  	<li>두울</li>,
  	<li>세엣</li>
];
  • JSX.Element[]Array<JSX:Element> type 의 축약형
const list3:Array<JSX.Element> = [
    <li>하나</li>,
    <li>두울</li>,
    <li>세엣</li>
];
  • handleChange 함수 추가
const handleChange = (e) => {

};
  • input 요소 추가 후 onChange 이벤트 추가
<input onChange={handleChange} type="text" />
  • handleChange 함수에 ChangeEvent<HTMLInputElement> 추가
    • input 요소에 change 이벤트가 일어났을 때 전달되는
      event 객체의 type 은 ChangeEvent<HTMLInputElement> 이다
const handleChange = (e:ChangeEvent<HTMLInputElement>) => {
	const value = e.target.value;
};
  • select 문 추가
<select>
    <option value="one">one</option>
    <option value="two">two</option>
</select>
  • handelSelectChange 함수 추가 및 ChangeEvent<HTMLSelectElement> 사용
const handelSelectChange = (e:ChangeEvent<HTMLSelectElement>) => {
	const value = e.target.value;
}
  • select 에 onChange 이벤트 추가
<select onChange={handelSelectChange}>
    <option value="one">one</option>
    <option value="two">two</option>
</select>

App5

  • src 폴더 안에 App5.tsx 생성
function App5() {
    return (
        <div>
            
        </div>
    );
}
  • name 은 null 이 가능한 type
let name:string|null = null;
  • 타입 선언
type MyData = {
  	id : number,
 	title : string|null
};
  • useData 함수 추가
const useData = (data:MyData) => {

};
  • 문자열의 길이 참조
    • ! : null 이 아닌게 확실해 그러니깐 참조하라는 뜻
let result = name!.length;
  • useData 함수 안에 문자열의 길이를 콘솔로 출력
    • ! 을 사용하면 에러 없이 강제로 참조 가능
const useData = (data:MyData) => {
	console.log(data.title!.length);
};
  • any 타입을 사용한 a 코드 추가
    • any 타입은 java 의 Object type 과 유사하게 어떤 type 이던지 담을 수 있다
    • 변수나 상수 또는 매개변수를 만들 때 plain javascript 처럼 사용하려면 any 타입을 쓰면 된다
let a:any = 10;
a = "kim";
a = () => {};;

App6

  • src 폴더 안에 App6.tsx 생성
function App6() {
    return <>
    
    </>
}
  • Product 타입 선언
type Product = {
    id : number,
    name : string,
    price : number
};
  • 시퀀스 값을 관리하기 위한 useState 함수 추가
const [seq, setSeq] = useState<number>(1);

  • 상품 목록을 관리하기 위한 useState 함수 추가
const [list, setList] = useState<Array<Product>>([]);

  • 상품 관련 테이블 추가
<div className="container">
    <h1>상품 목록</h1>
    <table>
        <thead>
            <tr>
                <th>아이디</th>
                <th>상품명</th>
                <th>가격</th>
            </tr>
        </thead>
        <tbody>
          	{list.map(item =>
				<tr key={item.id}>
					<td>{item.id}</td>
					<td>{item.name}</td>
					<td>{item.price}</td>
				</tr>
			)}
        </tbody>
    </table>
</div>
  • 상품명, 가격을 입력하는 텍스트 박스 추가
<input type="text" placeholder="상품명..."/>
<input type="text" placeholder="가격..."/>
  • useRef 함수 추가
const inputName = useRef(null);
const inputPrice = useRef(null);
  • input 텍스트 박스에 ref 속성 추가
<input ref={inputName} type="text" placeholder="상품명..."/>
<input ref={inputPrice} type="text" placeholder="가격..."/>
  • handleClick 함수 추가
    • 버튼을 눌렀을 때 실행할 함수
const handleClick = () => {

};
  • 버튼 추가 및 onClick 이벤트 추가
<button onClick={handleClick}>추가</button>
  • inputName , inputPrice 상수의 타입 명시
    • 어떤 객체의 참조값을 담을 것인지 type 을 명시한다
const inputName = useRef<HTMLInputElement>(null);
const inputPrice = useRef<HTMLInputElement>(null);
  • handleClick 함수 안에 입력한 상품명 읽어오는 코드 추가
const name = inputName.current!.value;
  • handleClick 함수 안에 입력한 가격 읽어오는 코드 추가
    • 참조된 내용은 string type 이기 때문에 숫자로 변경해 준다
const price = Number(inputPrice.current!.value);
  • handleClick 함수 안에 추가할 상품 코드 추가
const p1:Product = {
    id:seq,
    name:name,
    price:price
};
  • handleClick 함수 안에 상품 목록 상태 변경하는 코드 추가
setList([...list, p1]);
  • handleClick 함수 안에 시퀀스 증가 시키는 코드 추가
setSeq(seq+1);

App7

  • src 폴더 안에 App7.tsx 생성
function App7() {
    return <>
    
    </>
}
  • api 서버로부터 받아온 문자열이라고 가정하자
const json = `
	{"num":1, "name":"유재석", "addr":"압구정"}
`;
  • json 문자열을 parse 해서 실제 object 로 만든다
const obj = JSON.parse(json);
  • any type 을 MemberDto type 으로 변환
import type { MemberDto } from './types/type';
const dto1 = obj as MemberDto;
  • 해당 코드들의 결과를 출력한 p 코드 추가
<p>번호 : <strong>{dto1.num}</strong></p>
<p>이름 : <strong>{dto1.name}</strong></p>
<p>주소 : <strong>{dto1.addr}</strong></p>

이클립스 서버와 연결

axios 설치

npm install axios

bootstrap 설치

npm install bootstrap

react-bootstrap 설치

npm install react-bootstrap

Eclipes 는 spring09 로 서버 실행

  • vite.config.js 에 서버 관련 코드 추가
server: {
  	proxy: {
    	'/api': {  // 프록시할 경로
      	target: 'http://localhost:9000', // 백엔드 서버 주소
        	changeOrigin: true, 
          	secure: false,
            	rewrite: (path) => path.replace(/^\/api/, ''), // '/api' 제거 
    	},
      	'/upload':{ // upload 된 이미지를 로딩하기 위한 프록시 
        	target: 'http://localhost:9000', 
          	changeOrigin: true 
      	}
    },
},

고객 목록

  • src 폴더 안에 Client.tsx 생성
function Client() {
    return <>
    
    </>
}
  • div 요소 추가
<div className="container">
  	<h1>고객 목록</h1>
</div>
  • useEffect 함수 추가
useEffect(() => {
    axios.get("/api/v1/clients")
        .then(res => {
        console.log(res.data);
    })
        .catch(err => {
        console.log(err);
    })
}, []);

  • type.ts 에 ClientDto 타입 설정
    • readonly : 읽기 전용으로 수정 불가
    • | null : null 도 가능한 type
export type ClientDto  = {
    readonly num : number;
    userName : string;
    updatedAt : string;
    createdAt : string;
    birthday : string|null;
    formattedBirthday : string|null;
};
  • Client.tsx 에 ClientDto 타입을 사용하는 목록 관련 useState 함수 추가
    • 고객 목록을 상태값으로 관리한다
const [list, setList] = useState<ClientDto[]>([]);
  • then 문 안에 setList 코드 사용
    • 그냥 res.data 만 사용하면 any 타입으로 타입을 명확히 알 수가 없다
setList(res.data as ClientDto[]);
  • 고객 관련 정보를 출력하는 table 코드 추가
<table>
    <thead>
        <tr>
            <th>번호</th>
            <th>이름</th>
            <th>생일</th>
            <th>등록일</th>
        </tr>
    </thead>
    <tbody>
        {list.map(item =>
			<tr key={item.num}>
				<td>{item.num}</td>
				<td>{item.userName}</td>
				<td>{item.formattedBirthday}</td>
				<td>{item.createdAt}</td>
			</tr>
		)}
    </tbody>
</table>

  • 기존의 useEffect 안에 코드를 주석 처리하고 다시 axios 코드 추가
    • res.data 의 type 을 결정할 수 있다
axios.get<ClientDto[]>("/api/v1/clients")
.then(res => {
	setList(res.data);
})
.catch(err => console.log(err));

➜ 기존의 코드와 결과는 동일하다

고객 등록

  • Client.tsx 에 이름, 생일을 입력할 텍스트 박스와 추가 버튼 추가
이름 : <input type="text"/><br/>
생일 : <input type="date"/><br/>
<button>추가</button>
  • types.ts 에 ClientDto 타입에 값이 없을 수도 있는 데이터는 ? 를 붙여주기
    • ? = optional : 있거나 없거나 상관이 없다
export type ClientDto  = {
    readonly num? : number; // readonly 는 읽기 전용(수정 불가)
    userName : string;
    updatedAt? : string;
    createdAt? : string;
    birthday : string|null; // null 도 가능한 type
    formattedBirthday? : string|null;
};
  • 입력한 내용에 대한 useState 함수 추가
    • 입력한 내용을 상태값으로 관리
const [dto, setDto] = useState<ClientDto>({
    userName:"",
    birthday:""
});
  • 텍스트 박스에 name 속성 부여
이름 : <input type="text" name="userName"/><br/>
생일 : <input type="date" name="birthday"/><br/>
  • handleChange 함수 추가
    • input 요소에 change 이벤트 처리
const handleChange = (e:ChangeEvent<HTMLInputElement>) => {

};
  • 텍스트 박스에 onChange 이벤트 추가
이름 : <input onChange={handleChange} type="text" name="userName"/><br/>
생일 : <input onChange={handleChange} type="date" name="birthday"/><br/>
  • handleChange 함수 안에 setDto 사용
setDto({
	...dto,
  	[e.target.name] : e.target.value
});
  • handleClick 함수 추가
const handleClick = () => {

};
  • 버튼에 onClick 이벤트 추가
<button onClick={handleClick}>추가</button>
  • handleClick 함수 안에 try-catch 문 & async, await 코드 추가
const handleClick = async () => {
    try{
        // .post<ClientDto> 는 res.data 의 type 을 결정해준다
        const {data} = await axios.post<ClientDto>("/api/v1/clients", dto);
        // data 는 ClientDto type 이다
        // 여기서는 서버에 새로 데이터를 요청하지 않고 응답된 내용을 바로 list 에 추가해 보자
        setList([...list, data]);
    } catch(err){
        console.log(err);            
    }
};

운세

  • src 폴더 안에 components 폴더 생성 후 그 안에 Fortune.tsx 생성
function Fortune(props) {
    return <>
    
    </>
}
  • 오늘의 운세를 보여줄 코드 추가
<h3>오늘의 운세</h3>
<p style={{color:props.color}}>{props.fortuneToday}</p>
  • types.ts 에 FortuneProps 타입 추가
    • 특정 component 의 props type 을 미리 만들어 놓으면 좋다
export type FortuneProps = {
    color : string; // 글자의 색상
    fortuneToday : string; // 운세 정보
};
  • props 의 타입을 FortuneProps 로 선언
import type { FortuneProps } from '../types/type';

function Fortune(props:FortuneProps) {
    return <>
        <h3>오늘의 운세</h3>
        <p style={{color:props.color}}>{props.fortuneToday}</p>
    </>
}

App8

  • src 폴더 안에 App8.tsx 생성
function App8() {
    return <>
    
    </>
}
  • Fortune 사용
<div className="container">
    <h1>인덱스 페이지</h1>
    <Fortune />
</div>

<Fortune color="blue" fortuneToday={"동쪽으로 가면 귀인을 만나요"}/>

App9

  • src 폴더 안에 App9.tsx 생성
function App9() {
    return <>
    
    </>
}

Node.js

파일 탐색기를 열어 react 폴더에서 cmd 창 열기

  • 생성
npm create electron-vite@latest
  • yes
y
  • 프로젝트명을 hello-electron 로 설정하고 탬플릿을 React 로 설정
√ Project name: ... hello-electron
√ Project template: » React

  • hello-electron 로 이동
cd hello-electron
  • 의존 dependency 설치
npm install
  • 서버 실행
npm run dev

electron

  • react 와 상관없는 폴더
  • js 를 이용해 데스트탑의 관련된 기능

src

  • 화면 UI 담당

  • App.tsx 에 예시로 테스트할 p 요소 코드 추가


function App() {
    return <>
      	<p>나의 테스크탑 Application</p>
    </>
}

profile
학원 공부 내용 정리

0개의 댓글