로그인창 컴포넌트 / 검색창 컴포넌트 이런것들을 컴포넌트라 생각하면 된다.
우린 App이라는 함수 컴포넌트를 사용하는 것이다.
App.js에서 export하면 main.jsx가 받고
id가 root인 애한테 넘겨주는데 넘겨주는 곳이 index.html이다. 이제 여기서 화면에 뿌려주는 것이다.
App.jsx에서 Test06.jsx가 꾸며주는 거고 그걸 main.jsx가 받아서 index.html에 뿌려주는거
index.html이 렌더링 된다는 것이다.
빨간 네모가 자바스크립트 영역
밑에 노란색 영역이 jsx영역 - 이 영역을 자바스크립트 코드로 바꿔주는게 바벨의 역할이다.
jsx가 뭐인가? javaScript와 xml의 결합된 것이다.
return 문에 사용하는 문법 !
babel과 같은 변환기를 통해 JavaScript로 변환해준다.
- 태그는 반드시 닫아줘야한다.
- 최상단에서는 반드시 div로 감싸주어야한다. ( Fragment 사용, <></> 상황에 따라 )
- JSX안에서 자바스크립트 값을 사용하고 싶을 때는 { }를 사용한다. ★
- class 대신 className을 사용한다.
Props는 request.getParamer / param.name과 비슷한 역할
부모 컴포넌트에서 자식 컴포넌트로 전달되는 데이터나 함수이다
부모 const [name, setName]
부모가 변수를 가져야
자식이 가지고 있는 데이터를 위의 변수에 저장할 수 있고, 그 변수에 저장된 값을 자식한테 전달할 수 있는 것이다.
상태변수는 반드시 부모가 쥐고있어야한다.
모든 상태변수의 데이터는 누가? 부모가 쥐고있어야한다.
useState - 부모가 쥐고있다.
여기서 데이터는 고정이라서 name 변수가 절대 안바뀐다.
그래서 이제 나온게 useState가 나오게 된 것이다.
use 어쩌구저쩌구는 다 Hooks이다.
useState는 값이 유동적으로 변할 때 사용하며
[형식]은 const [상태데이터, 상태데이터의 값을 변경해주는 함수] = React.useState(초기값); 이렇게 되어있다.
여기까지가 어제했던 내용들 !
무료 이미지 다운받을 수 있다.
메모장에 5마리 정도 주소 붙여놓는다 !
day02_vite
src
App.jsx -- 메인
components
Test01.jsx
cat(Folder)
Cat.jsx
CatData.jsx
CatList.jsx
CatItem.jsx
css
Test06.css
App.jsx
Test01.jsx ~~~~~~~ Cat.jsx
CatData.jsx CatList.jsx
CatItem.jsx (~~DTO.java), 1인분
이런 구조 만드려고함 !
App.js
import Cat from './components/cat/Cat';
<Cat/>
import React from 'react';
import Test01 from './components/Test01';
import Test02 from './components/Test02';
import Test03 from './components/Test03';
import Test04 from './components/Test04';
import Test05 from './components/Test05';
import Test06 from './components/Test06';
import Cat from './cat/Cat';
const App = () => {
return (
<div>
{/*<Test01/> */}
{/*<Test02 />*/}
{/*<Test03/>*/}
{/*<Test04/>*/}
{/*<Test05/>*/}
{/*<Test06/>*/}
<Cat/>
</div>
);
};
export default App;
CatData.jsx
(데이터를 쥐고있는 애다.) -- 그러므로 컴포넌트 갖고있을 필요가 없다 !
얘는 데이터를 내보내야한다. -- export
export default [
{
id: 1,
img: 'https://cdn.pixabay.com/photo/2022/10/15/21/23/cat-7523894_1280.jpg',
title: '동글동글 귀여운 고양이'
},
{
id: 2,
img: 'https://cdn.pixabay.com/photo/2021/10/19/10/56/cat-6723256_1280.jpg',
title: '작고 귀여운고양이'
},
{
id: 3,
img: 'https://cdn.pixabay.com/photo/2023/07/19/04/56/european-shorthair-8136065_960_720.jpg',
title: '누워있는 귀여운 고양이'
},
{
id: 4,
img: 'https://cdn.pixabay.com/photo/2020/12/14/11/18/cat-5830643_1280.jpg',
title: '노란 귀여운 고양이'
},
{
id: 5,
img: 'https://cdn.pixabay.com/photo/2021/06/04/14/14/cat-6309964_1280.jpg',
title: '하얗고 귀여운 고양이'
}
]
얘네는 객체배열이다.
각각은 CatItem이다.
Cat.jsx
App.jsx
Test01.jsx ~~~~~~~ Cat.jsx
CatData.jsx CatList.jsx
CatItem.jsx (~~DTO.java), 1인분
CatData.jsx가 데이터를 가지고 있기 때무에 CatItem.jsx한테 줄 수 없으므로
데이터를 부모인 Cat.jsx가 상태변수로 쥐고있어야한다 !!
import dataList from './CatData';
catData.jsx에서 export로 내보낸 데이터를 Cat.jsx에서 import로 해서 받는 것이다.
const [list, setList] = useState(dataList);
데이터를 list가 쥐고있는 것이다.
<CatList list={ list } />
Cat.jsx에서 CatList.jsx list = { list }라는 이름으로 값을 보내주고 있는 것이다.
import React, { useState } from 'react';
import dataList from './CatData';
import CatList from './CatList';
const Cat = () => {
const [list, setList] = useState(dataList);
return (
<>
<section className='business'>
<div className='inner'>
<h2>고양이</h2>
<p>고양이들</p>
<CatList list={ list } />
</div>
</section>
</>
);
};
export default Cat;
CatList.jsx
const CatList = ({ list }) => {
여기로 5개의 데이터가 들어오는 것이다.
이제 map을 돌려서 5개의 데이터를 찍어줘야한다.
한사람 분의 데이터를 찍어주는 건 CatItem.jsx이므로
CatList.jsx에서 map을 돌릴 때 한 장의 사진을 찍어주는 건 CatItem.jsx이다.
CatList.jsx ---> CatItem.jsx ----> CatList.jsx ---> CatItem.jsx -----> CatList.jsx ---> CatItem.jsx
이런식으로 5번 해주는 것이다.
list.map(item => <CatItem item= { item }/>)
그러므로 CatItem으로 한 개의 데이터값을 보내줘야한다.
import React from 'react';
import CatItem from './CatItem';
const CatList = ({ list }) => {
return (
<ul className='list2'>
{
list.map(item => <CatItem key={ item.id } item= { item }/>)
}
</ul>
);
};
export default CatList;
CatItem.jsx
const CatItem = ({ item }) => {
여기서 위에서 보낸 item값을 받아줘야한다.
const { id, img, title } = item;
그다음 구조분해 할당을 해주면 된다.
import React from 'react';
import '../../css/reset.css';
import '../../css/style.css';
const CatItem = ({ item }) => {
const { id, img, title } = item;
return (
<li className='list2'>
<a href='#'>
<div>
<img src={ img } alt={title} />
</div>
</a>
</li>
);
};
export default CatItem;
reset.css
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700&display=swap');
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1.6;
font-size: 15px;
font-family: 'Noto Sans KR', sans-serif;
}
a {
line-height: 1.6;
font-size: 15px;
text-decoration: none;
color:#333;
}
ol, ul , li {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
style.css
.business {width: 100%;}
.business .inner {width: 1140px; margin: auto; padding: 100px 0;}
.business h2 {font-size: 35px; text-align: center; font-weight: 500; margin-bottom: 10px;}
.business h2 + p {text-align: center; font-size: 16px; margin-bottom: 40px;}
/* .business .list2 {display: flex; justify-content: space-between;} */
.business .list2 {display: flex; justify-content: center;}
.business .list2 li {width: 270px;}
.business .list2 li a div {width: 270px; height: 300px; overflow: hidden;}
.business .list2 li a div img {width: 270px; height: 250px; transition: 0.4s;}
.business .list2 li:hover a div img {transform:scale(1.03);}
.business .list2 li a h3 {padding: 20px 0; font-size: 20px; line-height: 1.4;
border-bottom: 1px solid #dcdcdc; margin-bottom: 20px;}
.business .list2 li a h3 span {display: block;}
.business .list2 li a p {font-size: 16px; color:#666;}
.business .more {width: 180px; margin:45px auto;}
.business .more a {display: block; height: 50px; border: 1px solid #999; text-align: center;
line-height: 50px; border-radius: 25px;}
day02_vite
src
App.jsx -- 메인
components
Test01.jsx
cat(Folder)
Cat.jsx
CatData.jsx
CatList.jsx
CatItem.jsx
sungJuk(Folder)
SungJuk.jsx
SungJukData.jsx ===> seq(10-14), name, kor, eng, math, tot, avg (총점과 평균은 계산)
SungJukList.jsx -- 데이터를 받아서 체크하는 곳이고
SungJukDTO.jsx
테이블 형식으로 출력하면 된다.
SungJukData.jsx
export default [
{
seq: 10,
name: '짱구',
kor: 90,
eng : 80,
math: 100
},
{
seq: 11,
name: '철수',
kor: 100,
eng : 90,
math: 100
},
{
seq: 12,
name: '훈이',
kor: 52,
eng : 44,
math: 22
},
{
seq: 13,
name: '맹구',
kor: 70,
eng : 83,
math: 95
},
{
seq: 14,
name: '유리',
kor: 73,
eng : 82,
math: 55
}
]
SungJuk.jsx
import React, { useState } from 'react';
import dataList from './SungJukData';
import SungJukList from './SungJukList';
import '../../css/sungJuk.css';
const SungJuk = () => {
const [list, setList ] = useState(dataList);
return (
<>
<section>
<div className='sungjukList'>
<h2>떡잎방범대 성적 리스트</h2>
<table border="1">
<thead>
<tr>
<th>번호</th>
<th>이름</th>
<th>국어</th>
<th>영어</th>
<th>수학</th>
<th>총점</th>
<th>평균</th>
</tr>
</thead>
<SungJukList list = { list }/>
</table>
</div>
</section>
</>
);
};
export default SungJuk;
SungJukList.jsx
import React from 'react';
import SungJukDTO from './SungJukDTO';
const SungJukList = ({ list }) => {
return (
<tbody>
{
list.map(item => <SungJukDTO key={item.seq} dto = { item } />)
}
</tbody>
);
};
export default SungJukList;
SungJukDTO.jsx
import React, { useState } from 'react';
const SungJukDTO = ({dto}) => {
const {seq, name, kor, eng, math} = dto;
const tot = kor + eng + math;
const avg = tot / 3.0;
return (
<tr>
<td>{ seq }</td>
<td>{ name }</td>
<td>{ kor }</td>
<td>{ eng }</td>
<td>{ math }</td>
<td>{ tot }</td>
<td>{ avg }</td>
</tr>
);
};
export default SungJukDTO;
sungJuk.css
.sungjukList {
width: 80%;
margin: 0 auto;
padding: 20px;
border-radius: 10px;
background-color: #f9f9f9;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.sungjukList h2 {
text-align: center;
margin-bottom: 20px;
color: #333;
font-size: 24px;
}
.sungjukList table {
width: 100%;
border-collapse: collapse;
font-family: 'Arial', sans-serif;
}
.sungjukList th, .sungjukList td {
padding: 12px 15px;
text-align: center;
border: 1px solid #ddd;
}
.sungjukList th {
background-color: #E8D8FF;
color: black;
font-weight: bold;
}
.sungjukList tr:nth-child(even) {
background-color: #f2f2f2;
}
.sungjukList tr:hover {
background-color: #EDEDED;
cursor: pointer;
}
.sungjukList td {
color: #555;
font-size: 16px;
}
.sungjukList th:first-child, .sungjukList td:first-child {
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
.sungjukList th:last-child, .sungjukList td:last-child {
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
day03 생성
App.js
import React from 'react';
import Test01 from './components/Test01';
const App = () => {
return (
<div>
<Test01/>
</div>
);
};
export default App;
Hooks - useRef
- 직접 DOM 요소에 접근해야 할 때, useRef 훅을 사용하여 DOM 요소에 직접 접근이 가능하다.
- 리렌더링을 하지 않는다. (계속 그 값을 유지할 때 써먹는다.)
Ref를 사용해야 할 때
1. 포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때
2. 애니메이션을 직접적으로 실행시킬 때
3. 서드 파티 DOM 라이브러리를 React와 같이 사용할 때
- event.preventDefault()
a 태그는 href를 통해 특정 사이트로 이동하거나,
submit 태그는 값을 전송하면서 창이 새로고침(reload) 된다.
이런 태그의 이벤트 기능을 preventDefault를 통하여 동작하지 않도록 막을 수 있다.
• 리액트에서 제공하는 대표적인 훅 중 하나이다.
• JavaScript 를 사용 할 때에는, 우리가 특정 DOM 을 선택해야 하는 상황에
getElementById, querySelector 같은 DOM Selector 함수를 사용해서 DOM 을 선택한다.
리액트에서는 직접 DOM 요소에 접근해야 할 때, useRef 훅을 사용하여 DOM 요소에 직접 접근이 가능하다.
• useRef 훅이 반환하는 ref 객체를 이용해서 자식 요소에 접근이 가능하다.
• input태그와 같이 사용자가 값을 직접 입력하는 html태그에 직접적으로 접근하여 값을 가져오는 것을 가능하게 한다.
리액트 컴포넌트는 State가 변할 때마다 다시 렌더링이 되면서 컴포넌트 내부 변수들이 초기화 된다.
하지만 Ref안에 있는 값은 아무리 변경해도 컴포넌트는 다시 렌더링 되지 않는다.
즉, State 대신 Ref를 사용한다면 불필요한 렌더링을 막을 수 있다.
또한 컴포넌트가 아무리 렌더링이 되어도 Ref안에 저장되어 있는 값은 변화되지 않고 그대로 유지 된다.
그래서 렌더링을 발생시키지 말아야 하는 값을 다룰 때 정말 편리하다.
1. Ref 객체를 만들어준다.
const nameRef = useRef();
2. 선택하고 싶은 DOM에 속성으로 ref 값을 설정해준다.
<input ref = { nameRef } />
3. Ref 객체의 current 값은 우리가 선택하고자 하는 DOM을 가리킨다.
그리고 포커싱을 해주는 DOM API focus()를 호출한다.
Test01.jsx
import React from 'react';
import { useState } from 'react';
const Test01 = () => {
const [id, setId] = useState('');
const [pwd, setPwd] = useState('');
return (
<div>
아이디 <input type='text' value={ id } />
<br/><br/>
비밀번호 <input type='password' value={ pwd }/>
<br/><br/>
<button>로그인</button>
<button>초기화</button>
</div>
);
};
export default Test01;
지금은 아무런 데이터도 입력할 수가 없다.
왜냐?? 빈값으로 설정해놨기 때문이다.
이런식으로 데이터값을 넣어놓으면 화면에 찍혀서 나온다.
import React from 'react';
import { useState } from 'react';
const Test01 = () => {
const [id, setId] = useState('hong');
const [pwd, setPwd] = useState('111');
return (
<div>
아이디 <input type='text' value={ id } />
<br/><br/>
비밀번호 <input type='password' value={ pwd }/>
<br/><br/>
<button>로그인</button>
<button>초기화</button>
</div>
);
};
export default Test01;
아이디 <input type='text' value={ id } onChange={ onInputId }/>
아이디에 있는 값을 변경해줬을 때의 함수 잡아주러 가자 !!
const onInputId = (e) => { --- event 받아서
console.log(e.target); -- event의 taret을 찍어보자
}
아이디 부분에 아무거나 입력해보면 이런식으로 Components에 target이 불러와지는거 확인할 수 있음.
이벤트가 발생한 타겟인 것이다.
import React from 'react';
import { useState } from 'react';
const Test01 = () => {
const [id, setId] = useState('hong');
const [pwd, setPwd] = useState('111');
const onInputId = (e) => {
console.log(e.target);
}
return (
<div>
아이디 <input type='text' value={ id } onChange={ onInputId }/>
<br/><br/>
비밀번호 <input type='password' value={ pwd }/>
<br/><br/>
<button>로그인</button>
<button>초기화</button>
</div>
);
};
export default Test01;
데이터값 입력할 수 있게하기
const onInputId = (e) => {
console.log(e.target);
const { value } = e.target;
setId(value)
}
이런식으로 하게되면 이제 데이터값을 입력할 수 있게되는 것이다.
import React from 'react';
import { useState } from 'react';
const Test01 = () => {
const [id, setId] = useState('hong');
const [pwd, setPwd] = useState('111');
const onInputId = (e) => {
console.log(e.target);
const { value } = e.target;
setId(value)
}
return (
<div>
아이디 <input type='text' value={ id } onChange={ onInputId }/>
<br/><br/>
비밀번호 <input type='password' value={ pwd }/>
<br/><br/>
<button>로그인</button>
<button>초기화</button>
</div>
);
};
export default Test01;
이제 입력이 잘되는것을 확인할 수 있다 !!
비밀번호에도 onChange={ onInputPwd } 추가하고 함수만들기 !
import React from 'react';
import { useState } from 'react';
const Test01 = () => {
const [id, setId] = useState('hong');
const [pwd, setPwd] = useState('111');
const onInputId = (e) => {
console.log(e.target);
const { value } = e.target;
setId(value)
}
const onInputPwd = (e) => {
console.log(e.target);
const { value } = e.target;
setPwd(value)
}
return (
<div>
아이디 <input type='text' value={ id } onChange={ onInputId }/>
<br/><br/>
비밀번호 <input type='password' value={ pwd } onChange={ onInputPwd }/>
<br/><br/>
<button>로그인</button>
<button>초기화</button>
</div>
);
};
export default Test01;
이제 초기화 함수를 할 것이다.
초기화 누르면 내가 적은값 다 사라지게 !!
<button onClick={ onReset }>초기화</button>
const onReset = (e) => {
setId(' ');
setPwd(' ');
}
import React from 'react';
import { useState } from 'react';
const Test01 = () => {
const [id, setId] = useState('');
const [pwd, setPwd] = useState('');
const onInputId = (e) => {
console.log(e.target);
const { value } = e.target;
setId(value)
}
const onInputPwd = (e) => {
//비구조 할당
//e.target - 이벤트 발생 대상
console.log(e.target);
const { value } = e.target;
setId(value)
}
const onReset = (e) => {
setId('');
setPwd('');
}
return (
<div>
아이디 <input type='text' value={ id } onChange={ onInputId }/>
<br/><br/>
비밀번호 <input type='password' value={ pwd } onChange={ onInputPwd }/>
<br/><br/>
<button>로그인</button>
<button onClick={ onReset }>초기화</button>
</div>
);
};
export default Test01;
아이디 <input type='text' name='id' value={ id } onChange={ onInputId }/>
함수로 value값만 받을 수 있는게 아닌 type, name, value 전부 다 받을 수 있다.
const onInputId= (e) => {
//비구조 할당
//e.target - 이벤트 발생 대상
console.log(e.target); //<input type='text' value='aa'>
const { type, name, value } = e.target; -- type, name 다 받을 수 있다.
setId(value)
}
import { useRef } from 'react';
import { useState } from 'react';
import { useRef, useState } from 'react';
같은 효과
[ focus함수 ]
1. Ref 객체를 만들어준다.
const nameRef = useRef();
2. 선택하고 싶은 DOM에 속성으로 ref 값을 설정해준다.
<input ref = { nameRef } />
3. Ref 객체의 current 값은 우리가 선택하고자 하는 DOM을 가리킨다.
그리고 포커싱을 해주는 DOM API focus()를 호출한다.
실행하면 아이디 입력창에 포커스가 가게하기 !!
const idRef = useRef(); -- 객체생성
아이디 <input type='text' name='id' value={ id } onChange={ onInputId } ref={idRef}/>
const onReset = (e) => {
setId('');
setPwd('');
idRef.current.focus();//포커스
}
초기화 누르면 아이디로 포커스가 된다.
비밀번호의 개수가 6자리 이상이면 로그인 버튼을 활성화시키기
<button disabled>로그인</button>
<button disabled={pwd.length < 6 }>로그인</button>
import React from 'react';
import { useRef, useState } from 'react';
const Test01 = () => {
const [id, setId] = useState('');
const [pwd, setPwd] = useState('');
const idRef = useRef();
const onInputId = (e) => {
//비구조 할당
//e.target - 이벤트 발생 대상
console.log(e.target);
const { value } = e.target;//<input type='text' name='id' value='aa'>
setId(value)
}
const onInputPwd = (e) => {
console.log(e.target);
const { value } = e.target;
setPwd(value)
}
const onReset = (e) => {
setId('');
setPwd('');
idRef.current.focus();//포커스
}
return (
<div>
아이디 <input type='text' name='id' value={ id } onChange={ onInputId } ref={idRef}/>
<br/><br/>
비밀번호 <input type='password' name='pwd' value={ pwd } onChange={ onInputPwd }/>
<br/><br/>
<button disabled={pwd.length < 6 }>로그인</button>
<button onClick={ onReset }>초기화</button>
</div>
);
};
export default Test01;
App.js
import Test02 from './components/Test02';
<Test02/>
import React from 'react';
import Test01 from './components/Test01';
import Test02 from './components/Test02';
const App = () => {
return (
<div>
{/*<Test01/>*/}
<Test02/>
</div>
);
};
export default App;
Test02.jsx
취미 선택할 때 선택한 값 즉, true인 값만 가져와야된다.
우리가 선택한게 무엇인지를 알아야한다 !
import React from 'react';
import { useState } from 'react';
const Test02 = () => {
const[chk, isChk] = useState(false);
return (
<div>
<input type='checkbox' checked={ chk }/>Have a nice day!!
</div>
);
};
export default Test02;
지금 이 상태에서는 값을 바꿀 수가 없다 !!
import React from 'react';
import { useState } from 'react';
const Test02 = () => {
const[chk, isChk] = useState(true);
const onInputChk = (e) => {
console.log(e.target); //<input type="checkbox" checked>
const { checked } = e.target;
isChk(checked);
}
return (
<div>
<input type='checkbox' checked={ chk } onChange={ onInputChk }/>Have a nice day!!
</div>
);
};
export default Test02;
div태그 안에 style로 만약 chk가 참이면 글자색을 blue 아니면 hotpink
<div style={{color: chk ? 'blue' : 'hotpink'}}>
<div style={{color: chk ? 'blue' : 'hotpink', fontSize: 25, margin: 30}}>
연결할 때는 콤마써야된다 (json 객체 형태로 넣는 것이므로!!)
Test03.css
.button {
padding: 20px 40px;
font-size: 25px;
}
.bg {
width: 100%;
height: 100%;
position: fixed;
left: 0;
top: 0;
background: #000;
opacity: 0.6;
}
.popup {
width: 400px;
height: 500px;
background: beige;
position: absolute;
left: 50%;
top: 50%;
padding: 30px;
box-sizing: border-box;
transform: translate(-50%, -50%);
}
.popup .closex {
position: absolute;
right: 20px;
bottom: 0px;
cursor: pointer;
border: 1px solid #000;
width: 50px;
height: 50px;
text-align: center;
line-height: 50px;
font-size: 40px;
}
.popup h2 {
font-size: 50px;
}
App.js
import React from 'react';
import Test01 from './components/Test01';
import Test02 from './components/Test02';
import Test03 from './components/Test03';
const App = () => {
return (
<div>
{/*<Test01/>*/}
{/*<Test02/>*/}
<Test03/>
</div>
);
};
export default App;
Test03Modal.jsx
import React from 'react';
const Test03Modal = () => {
return (
<>
<div className='bg'></div>
<div className='popup'>
<p className='closex' >X</p>
<h2>Have a nice day!!</h2>
</div>
</>
);
};
export default Test03Modal;
App.jsx
Test01.jsx Test02.jsx Test03.jsx
Test03Modal.jsx
화면에서 띄우는건 Test03.jsx / Test03Modal.jsx은 안 뜬다
Test03.jsx에서 띄워보자
Test03.jsx
import React from 'react';
import Test03Modal from './Test03Modal';
import '../css/Test03.css'
const Test03 = () => {
return (
<div>
<Test03Modal/>
</div>
);
};
export default Test03;
Test03Modal.jsx가 무조건 뜨게 하는게 싫다.
버튼잡아서 버튼 누르면 나오게 할 것이다.
1. 상태변수를 하나 잡아준다. open이라는 상태변수를 잡고 기본값은 false
2. open이 true이면 팝업 창이 뜨게한다.
import React from 'react';
import Test03Modal from './Test03Modal';
import '../css/Test03.css'
import { useState } from 'react';
const Test03 = () => {
const [open, isOpen] = useState(false);
const onOpen = () => {
isOpen(true);
}
return (
<div>
<button className='button' onClick={ onOpen }>팝업창</button>
{
open && <Test03Modal/>
}
</div>
);
};
export default Test03;
팝업창에서 X를 눌러서 팝업창을 닫히게 하고싶으면
상태변수 open 값을 false로 다시 만들어주면된다.
Test03Model.jsx에서
<p className='closex' onClick={ onClose }>X</p>
import React from 'react';
const Test03Modal = () => {
return (
<>
<div className='bg'></div>
<div className='popup'>
<p className='closex' onClick={ onClose }>X</p>
<h2>Have a nice day!!</h2>
</div>
</>
);
};
export default Test03Modal;
X버튼을 클릭했을 때 onClose함수를 실행하도록해서 open 값을 false로 만들어줘야하는데
상태변수가 Test03.jsx에 있기 때문에 부모에서 만든다음에 전달해줘야한다.
즉, 상태변수와 상태변수의 값을 변경시켜주는 함수는 같이 있어야한다 !!
Test03.jsx
const onClose = () => {
isOpen(false);
}
open && <Test03Modal onClose={ onClose }/>
import React from 'react';
import Test03Modal from './Test03Modal';
import '../css/Test03.css'
import { useState } from 'react';
const Test03 = () => {
const [open, isOpen] = useState(false);
//상태변수와 상태변수의 값을 변경시켜주는 함수는 같이 있어야한다.
const onOpen = () => {
isOpen(true);
}
const onClose = () => {
isOpen(false);
}
return (
<div>
<button className='button' onClick={ onOpen }>팝업창</button>
{
open && <Test03Modal onClose={ onClose }/>
}
</div>
);
};
export default Test03;
Test03Modal.jsx
const Test03Modal = ({ onClose }) => {
그리고 onClose를 받아줘야한다 !!
import React from 'react';
const Test03Modal = ({ onClose }) => {
return (
<>
<div className='bg'></div>
<div className='popup'>
<p className='closex' onClick={ onClose }>X</p>
<h2>Have a nice day!!</h2>
</div>
</>
);
};
export default Test03Modal;
Test04.jsx
Animal.jsx Display.jsx
동물 이름 입력 : 호랑이 내가 좋아하는 동물은 호랑이입니다.
상태변수는 부모인 Test04.jsx가 가지고있어야한다.
Test04.jsx
import React, { useState } from 'react';
import Animal from './Animal';
const Test04 = () => {
const [name, setName] = useState('호랑이');
//상태변수와 상태변수의 값을 변경시키는 함수는 같이있어야한다.
const onInputName = (e) => {
const{value} = e.target;
setName(value);
}
return (
<div>
<Animal name={name} onInputName={onInputName} />
</div>
);
};
export default Test04;
Animal.jsx
import React from 'react';
import Display from './Display';
const Animal = ({name, onInputName}) => {
return (
<div>
<h2>Animal 컴포넌트</h2>
<label>동물 이름을 입력하시오</label>
<input type='text' value={name} onChange={ onInputName }/>
<Display name={name}/>
</div>
);
};
export default Animal;
Display.jsx
import React from 'react';
const Display = ({name}) => {
return (
<div>
<h2>Display 컴포넌트</h2>
내가 좋아하는 동물은 {name}입니다.
</div>
);
};
export default Display;
Animal.jsx / Display.jsx 페이지들을 한 번에 다 읽은 다음에 데이터를 입력하면 즉각즉각 반응하는 거가
SPA( Single Page Application )라는 것이다 !!
Test05.jsx
Name.jsx Fruit.jsx Output.jsx
이름 입력: 과일명 입력: xx님이 좋아하는 과일은 xxx입니다.
상태변수: name, fruit
Test05.jsx
const onInputFruit = (e) => {
//const{value} = e.target;
//setFruit(value);
setFruit(e.target.value); -- 이렇게 한 번에 쓸 수 있다는 거 확인 !
}
import React from 'react';
import { useState } from 'react';
import Name from './Name';
import Fruit from './Fruit';
import Output from './Output';
const Test05 = () => {
const [name, setName] = useState('');
const [fruit, setFruit] = useState('');
const onInputName = (e) => {
const{value} = e.target;
setName(value);
}
const onInputFruit = (e) => {
//const{value} = e.target;
//setFruit(value);
setFruit(e.target.value);
}
return (
<div>
<Name name={name} onInputName={onInputName} />
<br/>
<Fruit fruit={fruit} onInputFruit={onInputFruit}/>
<Output name={name} fruit={fruit} />
</div>
);
};
export default Test05;
Name.jsx
import React from 'react';
import Output from './Output';
import Fruit from './Fruit';
const Name = ({name, onInputName}) => {
return (
<div>
<label>이름 입력 :</label>
<input type='text' value={name} onChange={ onInputName }/>
</div>
);
};
export default Name;
Fruit.jsx
import React from 'react';
import Output from './Output';
const Fruit = ({fruit, onInputFruit}) => {
return (
<div>
<label>과일명 입력 :</label>
<input type='text' value={fruit} onChange={ onInputFruit }/>
</div>
);
};
export default Fruit;
Output.jsx
import React from 'react';
const Output = ({name, fruit}) => {
return (
<div>
<br/>
<h3>{name}님이 좋아하는 과일은 {fruit}입니다.</h3>
</div>
);
};
export default Output;
Test06.jsx
회원가입할 때 상태변수를 하나하나 다 잡는 것보다 객체로 묶어버리는게 더 좋다.
const [dto, setDto] = useState({});
{} 객체라는 뜻
[] 배열이라는 뜻
const Test06 = () => {
const [dto, setDto] = useState({
name: '',
id: '',
pwd: ''
});
이렇게 잡게되면
<td><input type='text' name='dto.name'/></td>
이런식으로 dto.name이렇게 불러야되는데 귀찮다 !!
구조분해할당을 해주는 것
const {name, id, pwd} = dto;
<tr>
<th width='100'>이름</th>
<td><input type='text' name='name' onChange={ onInputName }/></td>
</tr>
<tr>
<th width='100'>아이디</th>
<td><input type='text' name='id' onChange={ onInputId }/></td>
</tr>
<tr>
<th width='100'>비밀번호</th>
<td><input type='password' name='pwd' onChange={ onInputPwd }/></td>
</tr>
그리고 이런식으로 onChange했을 때 함수가 딱 한 군데만 틀린데도 불구하고 세 번이나 써야한다.
const onInputName = (e) => {
const{value} = e.target;
setName(value);
}
const onInputId = (e) => {
const{value} = e.target;
setId(value);
}
const onInputPwd = (e) => {
const{value} = e.target;
setPwd(value);
}
회원가입의 회원이 7개의 항목을 입력해야하면 저걸 7번이나 써야한다.
달라지는건 어디에 넣을건지만 달라진다.
똑같은 문장을 쓰는 걸 제일 싫어하므로 한 번에 처리하자.
<tr>
<th width='100'>이름</th>
<td><input type='text' name='name' value={name} onChange={ onInput } ref={nameRef}/></td>
</tr>
<tr>
<th width='100'>아이디</th>
<td><input type='text' name='id' value={id} onChange={ onInput }/></td>
</tr>
<tr>
<th width='100'>비밀번호</th>
<td><input type='password' name='pwd' value={pwd} onChange={ onInput }/></td>
</tr>
const onInput = (e) => {
const {value} = e.target;
}
원래는 이런식으로 value값만 받아왔다. 우리가 입력한 값!만
const {name, value} = e.target;
근데 value만 받으면 문제가 되는게 name인지 id인지 pwd인지 알 수가 없으므로 name도 같이 받아오는 것이다.
이름 홍길동
아이디 hong
비밀번호 111 ---> 333으로 바꾸고싶으면 이름이랑 아이디는 그대로있어야한다.
바뀌는게 누가 바뀌는건지 체크를 해야한다.
동시에 바뀌는 것은 아니다 !!
기존값을 복제를 뜨고 name에 받아온 value값을 넣는 것이다.
setDto({
...dto,
[name] : value
});
초기화하기
const onReset = () => {
setDto({
name: '',
id: '',
pwd: ''
});
}
초기화 누를 때마다 focus가 들어가게 해주기
const nameRef = useRef();
<tr>
<th width='100'>이름</th>
<td><input type='text' name='name' value={name} onChange={ onInput } ref={nameRef}/></td>
</tr>
const onReset = () => {
setDto({
name: '',
id: '',
pwd: ''
});
nameRef.current.focus();
}
전체코드
import React from 'react';
import { useRef } from 'react';
import { useState } from 'react';
const Test06 = () => {
const nameRef = useRef();
const [dto, setDto] = useState({
name: '',
id: '',
pwd: ''
});
const {name, id, pwd} = dto;
const onInput = (e) => {
const {name, value} = e.target;
setDto({
...dto,
[name] : value
});
}
const onReset = () => {
setDto({
name: '',
id: '',
pwd: ''
});
nameRef.current.focus();
}
return (
<div>
<table border={1} cellPadding={5} cellSpacing='0'>
<tr>
<th width='100'>이름</th>
<td><input type='text' name='name' value={name} onChange={ onInput } ref={nameRef}/></td>
</tr>
<tr>
<th width='100'>아이디</th>
<td><input type='text' name='id' value={id} onChange={ onInput }/></td>
</tr>
<tr>
<th width='100'>비밀번호</th>
<td><input type='password' name='pwd' value={pwd} onChange={ onInput }/></td>
</tr>
<tr>
<td colSpan='2' align='center'>
<button onClick={ onReset }>초기화</button>
</td>
</tr>
</table>
</div>
);
};
export default Test06;
[HOMEWORK]
Test07Main.jsx(상태변수)(모든 버튼들도 부모가)
Test07Input.jsx Test07Print.jsx TestOutput.jsx
이름 입력 : (제대로 받았는지 체크함) xxx님
나이 입력 : 이 정보가 맞냐!? 체크 설문조사에 응해주셔서 감사합니다.
주소 입력 : <li>태그 이용해서
핸드폰 입력 : 이름 :
다음 나이 :
주소 :
핸드폰 :
이런식으로 입력받은 내용 한 번 더 출력
이전 다음
(입력한 정보가 잘 못 됐으면 이전 / 아니면 다음)
Test07.css
.wrap { width: 400px; border: 1px solid #000; padding: 30px; margin: 30px auto; }
.wrap p { margin-bottom: 10px; }
.wrap p label {display: inline-block; width: 80px; }
.wrap p input { margin-left: 10px; height: 30px; width: 200px; padding: 0 15px;
border: 1px solid #999; }
.wrap p:last-child { margin-top: 30px; }
.wrap p button { width: 150px; height: 40px; background: #333; color: #fff;
border: none; margin-right: 10px; }
.wrap ul li { border-bottom: 1px dotted #dcdcdc; line-height: 3; }
.wrap ul li span { display: inline-block; width: 80px; }
.wrap ul li em { margin-left: 10px; height: 30px; width: 200px; padding: 0 15px; }
.wrap h3 { text-align: center; font-size: 40px; font-weight: 500; }
.wrap h3 span { display: block; }
Test07Main.jsx
import React from 'react';
import { useState } from 'react';
import Test07Input from './Test07Input';
import Test07Print from './Test07Print';
import TestOutput from './Test07Output';
import '../css/Test07.css'
const Test07Main = () => {
const [dto, setDto] = useState({
name: '',
age: '',
addr: '',
phone: '',
});
const[count, setCount] = useState(1);
const onInput = (e) => {
const {name, value} = e.target;
setDto({
...dto,
[name] : value
});
}
return (
<div className='wrap'>
{
count === 1 && <Test07Input dto={dto} count={count} setCount={setCount} onInput={onInput}/>
}
{
count === 2 && <Test07Print dto={dto} count={count} setCount={setCount} />
}
{
count === 3 && <TestOutput dto={dto}/>
}
</div>
);
};
export default Test07Main;
Test07Input.jsx
import React from 'react';
const Test07Input = ({dto, setCount, onInput, count}) => {
return (
<div>
<p>
<label>이름 :</label>
<input type='text' name='name' value={dto.name} onChange={ onInput } /><br/>
</p>
<p>
<label>나이 :</label>
<input type='text' name='age' value={dto.age} onChange={ onInput } /><br/>
</p>
<p>
<label>주소 :</label>
<input type='text' name='addr' value={dto.addr} onChange={ onInput } /><br/>
</p>
<p>
<label>핸드폰 :</label>
<input type='text' name='phone' value={dto.phone} onChange={ onInput } /><br/>
</p>
<p style={{ textAlign: 'center' }}>
<button onClick={() => setCount(count + 1)}>다음</button>
</p>
</div>
);
};
export default Test07Input;
Test07Print.jsx
import React from 'react';
const Test07Print = ({dto, setCount, count}) => {
return (
<div>
<ul>
<li>이름 : {dto.name}</li>
<li>나이 : {dto.age}</li>
<li>주소 : {dto.addr}</li>
<li>핸드폰 : {dto.phone}</li>
</ul>
<p style={{ textAlign: 'center' }}>
<button onClick={() => setCount(count - 1)}>이전</button>
<button onClick={() => setCount(count + 1)}>다음</button>
</p>
</div>
);
};
export default Test07Print;
TestOutput.jsx
import React from 'react';
const TestOutput = ({dto}) => {
return (
<div>
<h3>
<span>{dto.name}님</span>
설문조사 감사합니다.
</h3>
</div>
);
};
export default TestOutput;
{ onNext } { onPrev } 있는 버전으로 고치고 + 구조분해할당도 집어넣으면 !
Test07Main.jsx
import React from 'react';
import { useState } from 'react';
import Test07Input from './Test07Input';
import Test07Print from './Test07Print';
import TestOutput from './Test07Output';
import '../css/Test07.css'
const Test07Main = () => {
const [dto, setDto] = useState({
name: '',
age: '',
addr: '',
phone: '',
});
const{ name, age, addr, phone } = dto;
const[count, setCount] = useState(1);
const onInput = (e) => {
const {name, value} = e.target;
setDto({
...dto,
[name] : value
});
}
const onNext = () => {
setCount(count + 1)
}
const onPrev = () => {
setCount(count - 1)
}
return (
<div className='wrap'>
{
count === 1 && <Test07Input dto={dto} onInput={onInput} onNext={onNext} />
}
{
count === 2 && <Test07Print dto={dto} onNext={onNext} onPrev={onPrev} />
}
{
count === 3 && <TestOutput name={name}/>
}
</div>
);
};
export default Test07Main;
Test07Input.jsx
import React from 'react';
const Test07Input = ({dto, onInput, onNext}) => {
const{ name, age, addr, phone } = dto;
return (
<div>
<p>
<label>이름 :</label>
<input type='text' name='name' value={name} onChange={ onInput } /><br/>
</p>
<p>
<label>나이 :</label>
<input type='text' name='age' value={age} onChange={ onInput } /><br/>
</p>
<p>
<label>주소 :</label>
<input type='text' name='addr' value={addr} onChange={ onInput } /><br/>
</p>
<p>
<label>핸드폰 :</label>
<input type='text' name='phone' value={phone} onChange={ onInput } /><br/>
</p>
<p style={{ textAlign: 'center' }}>
<button onClick={onNext}>다음</button>
</p>
</div>
);
};
export default Test07Input;
Test07Print.jsx
import React from 'react';
const Test07Print = ({dto, onNext, onPrev}) => {
const{ name, age, addr, phone } = dto;
return (
<div>
<ul>
<li>이름 : <em>{name}</em></li>
<li>나이 : <em>{age}</em></li>
<li>주소 : <em>{addr}</em></li>
<li>핸드폰 : <em>{phone}</em></li>
</ul>
<p style={{ textAlign: 'center' }}>
<button onClick={onPrev}>이전</button>
<button onClick={onNext}>다음</button>
</p>
</div>
);
};
export default Test07Print;
TestOutput.jsx
import React from 'react';
const TestOutput = ({name}) => {
return (
<div>
<h3>
<span>{name}님</span>
설문조사 감사합니다.
</h3>
</div>
);
};
export default TestOutput;
'REACT' 카테고리의 다른 글
DAY 76 - React HOMEWORK (2024.10.24) (1) | 2024.10.24 |
---|---|
DAY 76 - React - Hook: useEffect / 컴포넌트별 CSS (2024.10.24) (3) | 2024.10.24 |
DAY 74 - React (2024.10.22) (2) | 2024.10.22 |
DAY 74 - ES6 (2024.10.22) (0) | 2024.10.22 |
DAY 73 - ES6 (2024.10.21) (0) | 2024.10.21 |