SPA(Single Page Application)
컴포넌트 - App.js (메인화면 단을 가리키는 함수 하나하나를) -- 메인함수 (화면 꾸며주는 역할)
TestMain.jsx TestInput.jsx 전부 컴포넌트 -- 독립적으로 잡혀있기 때문에 재사용 목적으로 언제든지 다시 부를 수 있다.
클래스 컴포넌트는 사라짐 / 함수형 컴포넌트만 보면 된다.
JSX 규칙을 따라간다. 자바스크립트와 XML이 섞임
return 안에 있는 구역이 전부 jsx 구역
예전에는 바벨을 깔아서 직접 교환하라 했지만 지금은 노드가 알아서 해준다.
Props -- 데이터 전달
useState -- 현재 갖고 있는 값을 바꾸고싶다.
useRef -- 현재 갖고있는 값 바꾸고싶지 않다.
이제 숙제 검사 !! 어제 블로그로 가자.
Test06.jsx
<h3>이름 : { name }</h3>
<h3>아이디 : { id }</h3>
<h3>비밀번호 : { pwd }</h3>
데이터 찍어보는거 추가하기
const onInput = (e) => {
const {name, value} = e.target;
setDto({
...dto, //먼저 객체를 복사하고
[name] : value //원하는 값(name or id or pwd)만 수정한다.
//복사하지 않으면 이전 값은 초기화 된다.
});
}
[name] : value 여기서 name을 문자열이 아니라 변수로 사용하기 위해서 "name"에서 ""를 빼주는 역할이
[ ] 이라고 보면 된다.
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 //원하는 값(name or id or pwd)만 수정한다.
//복사하지 않으면 이전 값은 초기화 된다.
});
}
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>
<hr/>
<h3>이름 : { name }</h3>
<h3>아이디 : { id }</h3>
<h3>비밀번호 : { pwd }</h3>
</div>
);
};
export default Test06;
- public에 있는 이미지 폴더는 index.html를 기준으로부터 상대경로를 지정해야 한다.
- index.html 안의 <div id="root"></div> 이곳으로 렌더링 되기 때문이다.
- 단 ./ 를 생략해서는 안 된다.
Test08Gallery.jsx
Test08Data.jsx Test08View.jsx
Test08Big.jsx Test08List.jsx
(한 장의 사진은 크게) Test08Item.jsx
{ id: 1, img: './image/dog01.jpg', title: '' },
화면에 띄워주는건 index.html으로 띄워주는 것이므로 public 입장에 두고 거기에 image다 해서 들어와야한다.
헷갈리면 안 된다. 최종으로 뜨는건 index.html이므로 저 div가 화면에 보이는 곳이다.
그러므로 image폴더 위치를 잘 생각해야함 !!!
Test08Data.jsx
export default [
{ id: 1, img: './image/dog01.jpg', title: '시무룩한 골든리트리버' },
{ id: 2, img: './image/dog02.jpg', title: '시무룩한 시바견' },
{ id: 3, img: './image/dog03.jpg', title: '꼬질한 강아지' },
{ id: 4, img: './image/dog04.jpg', title: '새하얀 포메라니언' },
{ id: 5, img: './image/dog05.jpg', title: '하찮게 귀여운 강아지' },
{ id: 6, img: './image/dog06.jpg', title: '눈 감고있는 강아지' },
{ id: 7, img: './image/dog07.jpg', title: '귀여운 푸들' },
{ id: 8, img: './image/dog08.jpg', title: '귀 쫑긋 강아지' }
]
우리의 위치는 index.html이므로 ./ 현재위치에서 image폴더에 있는 사진들 가져와라 하는 것이다 !!
Test08Data.jsx에서 image 폴더로 가는게 아니다 !!!!!
Test08Gallery.jsx
Test08Data.jsx에서 export한 데이터리스트 받자 !!
import React from 'react';
import dataList from './Test08Data';
import { useState } from 'react';
import Test08View from './Test08View';
import '../css/Test08.css'
const Test08Gallery = () => {
const [list, setList] = useState(dataList);
return (
<div className='wrap2'>
<Test08View list={list}/>
</div>
);
};
export default Test08Gallery;
list 들고 Test08View.jsx로 가자 !!
Test08View.jsx
import React from 'react';
import Test08Big from './Test08Big';
import Test08List from './Test08List';
const Test08View = ({list}) => {
return (
<div className='bigview'>
<Test08Big/>
<Test08List list={list}/>
</div>
);
};
export default Test08View;
Test08List.jsx로 list 들고가자 !!
Test08List.jsx
받은 list를 하나씩 해서 Test08Item.jsx로 보내자 !!
import React from 'react';
import Test08Item from './Test08Item';
const Test08List = ({list}) => {
return (
<ul className='list'>
{
list.map(item => <Test08Item key={item.id} item={item}/>)
}
</ul>
);
};
export default Test08List;
Test08Item.jsx
import React from 'react';
const Test08Item = ({item}) => {
const{id, img, title} = item
return (
<li>
<img src={img} alt={title}/>
</li>
);
};
export default Test08Item;
위에 이미지 한 개가 크게 보이게 하는 것을 하고싶다 !!
Test08View.jsx
import React from 'react';
import Test08Big from './Test08Big';
import Test08List from './Test08List';
const Test08View = ({list}) => {
return (
<div className='bigview'>
<Test08Big/>
<Test08List list={list}/>
</div>
);
};
export default Test08View;
여기서 Test08Big으로 갈 때 하나의 이미지를 가지고 가야하는데
데이터를 쥐고 있는게 TestGalley이다.
대표적으로 하나의 이미지만 쥐고있는게 필요하다 !!
Test08Gallery.jsx
여기서 하나의 이미지만 가지고 있는 게 필요하다.
const[one, setOne] = useState(list[1]);
<Test08View list={list} one={one}/>
one 전달해준다.
import React from 'react';
import dataList from './Test08Data';
import { useState } from 'react';
import Test08View from './Test08View';
import '../css/Test08.css'
const Test08Gallery = () => {
const [list, setList] = useState(dataList);
const[one, setOne] = useState(list[1]);
return (
<div className='wrap2'>
<Test08View list={list} one={one}/>
</div>
);
};
export default Test08Gallery;
Test08View.jsx
const Test08View = ({list, one}) => {
one 받아주고
<Test08Big one={one}/>
one을 보낸다.
import React from 'react';
import Test08Big from './Test08Big';
import Test08List from './Test08List';
const Test08View = ({list, one}) => {
return (
<div className='bigview'>
<Test08Big one={one}/>
<Test08List list={list}/>
</div>
);
};
export default Test08View;
Test08Big.jsx
import React from 'react';
const Test08Big = ({one}) => {
const {id, img, title} = one
return (
<div className='bigimg'>
<h2>{title}</h2>
<img src={img} alt={title} />
</div>
);
};
export default Test08Big;
이제 클릭하면 저 큰 이미지가 바뀌게 하기 !!
Test08Item.jsx -- 여기가 시작 !!! 이미지 누르면 onView 함수를 잡아줬다.
import React from 'react';
const Test08Item = ({item, onView}) => {
const{id, img, title} = item
return (
<li onClick={ onView }>
<img id={id} src={img} alt={title}/>
</li>
);
};
export default Test08Item;
Test08Gallery.jsx (onView)
Test08Data.jsx Test08View.jsx (onView)
Test08Big.jsx Test08List.jsx (onView)
(한 장의 사진은 크게) Test08Item.jsx(onView)
이 구조를 잘 생각해보면 저 onView함수는 최상단에 있는 부모 Test08Gallery.jsx부터 타고타고 보내야함 !
Test08Gallery.jsx
const onView = (e) => {
console.log(e.target);
const{id} = e.target; -- 고유한 키 값이 필요 !! id를 이용 !!
setOne(list[id-1]) -- 대신 그냥 id하면 배열에서는 0부터 시작이므로 id-1을 해줘야한다 !
}
import React from 'react';
import dataList from './Test08Data';
import { useState } from 'react';
import Test08View from './Test08View';
import '../css/Test08.css'
const Test08Gallery = () => {
const [list, setList] = useState(dataList);
const[one, setOne] = useState(list[0]);
const onView = (e) => {
console.log(e.target);
const{id} = e.target;
setOne(list[id-1])
}
return (
<div className='wrap2'>
<Test08View list={list} one={one} onView={onView}/>
</div>
);
};
export default Test08Gallery;
Test08View.jsx
import React from 'react';
import Test08Big from './Test08Big';
import Test08List from './Test08List';
const Test08View = ({list, one, onView}) => {
return (
<div className='bigview'>
<Test08Big one={one}/>
<Test08List list={list} onView={onView}/>
</div>
);
};
export default Test08View;
Test08List.jsx
import React from 'react';
import Test08Item from './Test08Item';
const Test08List = ({list, onView}) => {
return (
<ul className='list'>
{
list.map(item => <Test08Item key={item.id} item={item} onView={onView}/>)
}
</ul>
);
};
export default Test08List;
Test08Item.jsx --- 최종으로 여기로 온다 !!
import React from 'react';
const Test08Item = ({item, onView}) => {
const{id, img, title} = item
return (
<li onClick={ onView }>
<img id={id} src={img} alt={title}/>
</li>
);
};
export default Test08Item;
이미지 누를 때마다 바뀐다 !!
src 안 이미지 파일 처리
src 안에 있는 이미지 파일 처리는 참조변수를 사용한다.
[형식]
import 참조변수 from '이미지경로';
이번엔 src 안에 image 폴더를 잡아보자 !
Test09.jsx
import React from 'react';
import img01 from '../image/img01.jpg'
import img02 from '../image/img02.jpg'
import img03 from '../image/img03.jpg'
import img04 from '../image/img04.jpg'
const Test09 = () => {
return (
<div>
<img src={img01} alt='짱구01' style={{width: '200px', height: '200px'}} />  
<img src={img02} alt='짱구02' style={{width: '200px', height: '200px'}} />  
<img src={img03} alt='짱구03' style={{width: '200px', height: '200px'}} />  
<img src={img04} alt='짱구04' style={{width: '200px', height: '200px'}} />  
</div>
);
};
Test10.jsx
이제는 데이터파일을 가져오는게 아니라 추가버튼을 누를 때마다 데이터가 쌓이게 하고싶은거 !! (list에 쌓이게 !)
const [list, setList] = useState([]);
지금은 배열 값 비어있다는 것 !! 하나도 안 갖고있다.
<ul>
{
list.map((item, index) => <li key={ index }>
{ item.name } / { item.age }
</li>)
}
</ul>
이렇게해서 입력한 값 찍어주려고 하는 것 !
<form onSubmit={ onAdd }>
onAdd 함수 잡으러 가자 !!
submit은 페이지를 이동시키는 것이다. 넘어가려고 한다.
이런식으로 넘어가버리니까 못가게 할 것이다.
const onAdd = (e) => {
e.preventDefault(); // 브라우저의 고유한 동작을 중단시키는 역할
}
이제 추가 버튼을 눌러도 넘어가지 않는다.
배열은 수정이 아니라 추가다 !!!!
const onAdd = (e) => {
e.preventDefault(); // 브라우저의 고유한 동작을 중단시키는 역할
if(!name || !age)
return;
setList([
...list,
dto
]);
}
const onAdd = (e) => {
e.preventDefault(); // 브라우저의 고유한 동작을 중단시키는 역할
if(!name || !age)
return;
setList([
...list,
{
name: name,
age: age
}
]);
}
const onAdd = (e) => {
e.preventDefault(); // 브라우저의 고유한 동작을 중단시키는 역할
if(!name || !age)
return;
setList([
...list,
{
name,
age
}
]);
}
3개 다 같은 결과 !!
값을 입력하고 또 하려고 하면 입력창 값을 초기화 시켜줘야한다 !!
//초기화
setDto({
name: '',
age: ''
})
입력하고 나면 이름에 focus가게하기 !
import { useRef } from 'react';
const nameRef = useRef();
이름 : <input type='text' name='name' value={ name } onChange={ onInput } ref={nameRef}/>
nameRef.current.focus();
얘네는 유일한 키값이 없다. 그러므로 똑같이 홍길동을 두 번 추가해도 상관이 없어진다.
그래서 이 때 필요한게 ref이다.
const seq = useRef(1); //1 2 3 4 5 6 7 ~~~
이렇게 잡으면 숫자가 순서대로 커진다.
setList([
...list,
{
seq: seq.current++,
name,
age
}
]);
값을 넣을 때마다 seq.current++ 하면 증가하게 된다.
앞에 이름은 맘대로!!
<ul>
{
list.map((item, index) => <li key={ index }>
{item.seq} / { item.name } / { item.age }
</li>)
}
</ul>
import React from 'react';
import { useRef } from 'react';
import { useState } from 'react';
const Test10 = () => {
const nameRef = useRef();
const seq = useRef(1); //1 2 3 4 5 6 7 ~~~
const [dto, setDto] = useState({ //1인분
name: '',
age: '',
});
const{ name, age } = dto;
const [list, setList] = useState([]);
const onInput = (e) => {
console.log(e.target);
const {name, value} = e.target;
setDto({
...dto,
[name] : value
});
}
const onAdd = (e) => {
e.preventDefault(); // 브라우저의 고유한 동작을 중단시키는 역할
if(!name || !age)
return;
setList([
...list,
{
seq: seq.current++,
name,
age
}
]);
//초기화
setDto({
name: '',
age: ''
})
nameRef.current.focus();
}
return (
<div>
<form onSubmit={ onAdd }>
이름 : <input type='text' name='name' value={ name } onChange={ onInput } ref={nameRef}/>
<br/>
나이 : <input type='text' name='age' value={ age } onChange={ onInput }/>
<br/>
<button type='submit'>추가</button>
</form>
<hr/>
<ul>
{
list.map((item, index) => <li key={ index }>
{item.seq} / { item.name } / { item.age }
</li>)
}
</ul>
</div>
);
};
export default Test10;
★Test11.jsx
헷갈린다,,, 복습하기 !!!!!!!
import React from 'react';
import { useState } from 'react';
const dataList = [
{ id: 1, name: 'chk1', text: '연령(만 14세 이상) 확인(필수)', isChk: false},
{ id: 2, name: 'chk2', text: '개인정보 위탁 처리 동의(필수)', isChk: false},
{ id: 3, name: 'chk3', text: '개인정보 수집 및 이용에 대한 동의(필수)', isChk: false},
{ id: 4, name: 'chk4', text: '이벤트 우대 혜택 동의 안내(선택)', isChk: false},
]
const Test11 = () => {
const [list, setList]= useState(dataList);
const onChk = (e) => {
const {name, checked} = e.target;
if(name === 'all'){
setList(list.map(item => {
return {
...item, //밖을 { }로 감싸고 있는 객체이므로 수정이다.
isChk: checked //나머지애들은 유지하되 isChk만 바꾼다.
}
}))
}else{
//setList(list로 map을 돌리면서 선택한 name과 같은 것을 찾아서 isChk로 변경한다.)
setList(list.map(item => item.name === name ? {...item, isChk: checked } : item ));
}
}
return (
<div>
<p>
<input type='checkbox' name='all'onChange={ onChk }/>
<label>약관동의</label>
</p>
<hr/>
{
list.map(item => <p key={ item.id }>
<input type='checkbox' name={ item.name } checked={ item.isChk } onChange={ onChk }/>
<label>{ item.text }</label>
</p>)
}
</div>
);
};
export default Test11;
밑에 항목이 일부라도 체크가 취소되면 전체선택이 풀려야한다.
전체선택 checked가 false가 되어야 전체선택이 풀리므로 !!
false인 조건을 체크해야한다
<p>
<input type='checkbox' name='all'onChange={ onChk }
checked={ list.filter(item => item.isChk !== true ).length < 1 }/>
<label>약관동의</label>
</p>
이건 추천 X
<input type='checkbox' name='all'onChange={ onChk }
checked={ list.filter(item => !item.isChk).length < 1 }/>
true인지 물어보지 말고 !! ! 느낌표 연산자로 체크하기 !!
<input type='checkbox' name='all'onChange={ onChk }
checked={ list.filter(item => item.isChk).length === list.length }/>
이 방법이 더 좋을듯?
전체코드
import React from 'react';
import { useState } from 'react';
const dataList = [
{ id: 1, name: 'chk1', text: '연령(만 14세 이상) 확인(필수)', isChk: false},
{ id: 2, name: 'chk2', text: '개인정보 위탁 처리 동의(필수)', isChk: false},
{ id: 3, name: 'chk3', text: '개인정보 수집 및 이용에 대한 동의(필수)', isChk: false},
{ id: 4, name: 'chk4', text: '이벤트 우대 혜택 동의 안내(선택)', isChk: false},
]
const Test11 = () => {
const [list, setList]= useState(dataList);
const onChk = (e) => {
const {name, checked} = e.target;
if(name === 'all'){
setList(list.map(item => {
return {
...item, //밖을 { }로 감싸고 있는 객체이므로 수정이다.
isChk: checked //나머지애들은 유지하되 isChk만 바꾼다.
}
}))
}else{
//setList(list로 map을 돌리면서 선택한 name과 같은 것을 찾아서 isChk로 변경한다.)
setList(list.map(item => item.name === name ? {...item, isChk: checked } : item ));
}
}
return (
<div>
<p>
<input type='checkbox' name='all'onChange={ onChk }
checked={ list.filter(item => item.isChk).length === list.length }/>
<label>약관동의</label>
</p>
<hr/>
{
list.map(item => <p key={ item.id }>
<input type='checkbox' name={ item.name } checked={ item.isChk } onChange={ onChk }/>
<label>{ item.text }</label>
</p>)
}
</div>
);
};
export default Test11;
day04
cd day04
npm start
Hooks - useEffect란?
- useEffect는 렌더링, 혹은 변수의 값 혹은 오브젝트가 달라지게 되면,
그것을 인지하고 업데이트를 해주는 함수이다.
- useEffect는 콜백 함수를 부르게 되며, 렌더링 혹은 값, 오브젝트의 변경에 따라
어떠한 함수 혹은 여러 개의 함수들을 동작시킬 수 있다.
- 렌더링 후 useEffect는 무조건 한번은 실행된다.
useState와 useEffect는 같이 쓰인다.
[형식]
① 컴포넌트가 나타날 때 딱 1번만 함수가 호출
useEffect( () => {
}, [ ]);
② 특정 props가 바뀔 때마다 함수가 호출
useEffect( () => {
}, [ props ]);
useEffect 라는 Hook을 사용하여 할 수 있는 3가지 동작
- 컴포넌트가 마운트 됐을 때 (처음 나타났을 때)
- 언 마운트 됐을 때 (사라질 때)
- 업데이트될 때 (특정 props가 바뀔 때)
[ ]로 설정하면 컴포넌트가 처음 나타날 때만 useEffect에 등록한 함수가 호출 한다.
useEffect 에서는 함수를 반환 할 수 있는데 이를 cleanup 함수라고 부른다.
cleanup 함수는 useEffect 에 대한 뒷정리를 해준다고 이해하면 되는데, [ ] 안에 내용이 비어 있는 경우에는 컴포넌트가 사라질 때 cleanup 함수가 호출된다.
//e.clientX, e.clientY
//브라우저에서 사용자에게 웹페이지가 보여지는 영역을 기준으로 좌표를 표시
함수형 업데이트
- 비동기적인 방법을 해결하기 위해서 우리는 함수형 업데이트(functional update)를 사용할 수 있다.
즉 setState에 값을 그대로 전달하는 것이 아니라 함수를 전달하는 것이다.
Test01.jsx
const name = '카리나,아이유,수지,공유,이동욱,윈터,김세정,이제훈,설인아,유연석,안보현'.split(',');
쉼표로 하나하나 잘리면서 name[0] name[1] 배열로 잡힌다.
import React from 'react';
import { useState } from 'react';
const Test01 = () => {
const names = '카리나,아이유,수지,공유,이동욱,윈터,김세정,송강,한소희,차은우,안보현'.split(',');
const [name, setName] = useState('홍길동');
const [age, setAge] = useState(25);
const onName = () => {
const index = Math.floor(Math.random() * 11) //버림, 0 ~ 10
setName(names[index])
}
const onAge = () => {
setAge(age + 1)
}
return (
<div>
<button onClick={ onName }>이름 변경</button>
<button onClick={ onAge }>나이 변경</button>
<hr/>
<h1>{ name }</h1>
<h1>{ age }</h1>
</div>
);
};
export default Test01;
useEffect(() => {
console.log('안녕하세요');
});
처음실행하자마자
마운트 되자마자 저걸 실행해서 안녕하세요가 찍히게된다.
근데 왜 2번이 찍힐까??
실행하면 콘솔 창에 UseEffect는 왜 두 번 실행되는 걸까?
[해결 방법]
index.js
=> <React.StrictMode> 부분을 주석으로 처리
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
//<React.StrictMode>
<App />
//</React.StrictMode>
);
React의 Strict Mode ?
StrictMode는 리액트에서 제공하는 검사 도구이다.
개발 모드일 때 디버그를 통하여, 이 태그로 감싸져있는 App 컴포넌트와 자손까지 검사하는 것이다.
안전하지 않은 생명 주기를 가진 컴포넌트, 권장되지 않은 부분, 배포 후 문제가 될 수 있는 부분들까지 미리 확인하는 것이다.
creat-react-app으로 앱을 만들었기 때문에 기본적으로 생성되어 랜더링을 두 번이나 했었던 것이다.
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
//<React.StrictMode>
<App />
//</React.StrictMode>
);
// 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();
App만 렌더링되게 하면 된다.
한 번만 나오게 된다 !!
값이 바뀔 때마다 useEffect는 계속 실행되기 때문에 계속 안녕하세요가 찍혀서 나온다 !!
변화가 있을 때마다 사용되니 과부하가 일어나서 useEffect는 거의 사용하지 않는다.
마운트가 될 때 1번만 실행하고싶으면 ???
useEffect(() => {
console.log('안녕하세요');
}, [ ]);
이렇게하면 된다 !
그럼 처음에만 한 번 안녕하세요가 찍히고 값이 바뀌더라도 안녕하세요가 더이상 찍히지 않는다.
마운트 될 때랑 name값이 바뀔 때 실행하고싶으면?
useEffect(() => {
console.log('안녕하세요');
}, [name]);
나이 바뀔 때는 실행안되고 이름이 바뀔 때만 실행 된다 !!
전체코드
import React from 'react';
import { useEffect } from 'react';
import { useState } from 'react';
const Test01 = () => {
const names = '카리나,아이유,수지,공유,이동욱,윈터,김세정,송강,한소희,차은우,안보현'.split(',');
const [name, setName] = useState('홍길동');
const [age, setAge] = useState(25);
const onName = () => {
const index = Math.floor(Math.random() * 11) //버림, 0 ~ 10
setName(names[index])
}
const onAge = () => {
setAge(age + 1)
}
//거의 사용X
//값이 바뀌기만 하면 실행된다.
//불필요한 사용이 많다.
/*
useEffect(() => {
console.log('안녕하세요');
});
*/
/*
useEffect(() => {
console.log('안녕하세요');
}, []);
*/
//마운트, name값이 바뀔 때만 실행
useEffect(() => {
console.log('안녕하세요');
}, [name]);
return (
<div>
<button onClick={ onName }>이름 변경</button>
<button onClick={ onAge }>나이 변경</button>
<hr/>
<h1>{ name }</h1>
<h1>{ age }</h1>
</div>
);
};
export default Test01;
Test02Sub.jsx
import React from 'react';
import { useState } from 'react';
const Test02Sub = () => {
const [x, setX] = useState(0);
const [y, setY] = useState(0);
return (
<div>
<h2>마우스 좌표</h2>
<div style={{border: '1px solid #000', width: 400, padding: 30, margin: 15}}>
<h3>X축 : { x }, Y축 : { y }</h3>
</div>
</div>
);
};
export default Test02Sub;
Test02.jsx
import React from 'react';
import Test02Sub from './Test02Sub';
const Test02 = () => {
return (
<div>
<Test02Sub/>
</div>
);
};
export default Test02;
이제 여기서 마우스가 움직일 때마다 좌표값이 바뀌게 할 것이다.
이 때 마우스라는 이벤트는 윈도우에서 일어나는 이벤트인데 이 이벤트를 어디서 생성할 것이냐??
Test02Sub.jsx에서 useEffect를 사용해야한다.
useEffect(() => {
console.log('useEffect');
window.addEventListener('mousemove', onMove); //이벤트(윈도우 환경에서 이벤트를 발생하는 거 체크한다는 말)
//[]로 지정하면, 컴포넌트가 사라질 때 cleanup 함수가 호출된다.
}, []);
mousemove 이벤트가 일어나면 onMove 함수가 일어나게 !!
onMove함수 잡아주러 가자 !
const onMove = (e) => {
//브라우저에서 사용자가 웹페이지에 보여지는 영역을 기준으로 표시
setX(e.clientX);
setY(e.clientY);
}
useEffect(() => {
console.log('useEffect');
window.addEventListener('mousemove', onMove); //이벤트(윈도우 환경에서 이벤트를 발생하는 거 체크한다는 말)
//[]로 지정하면, 컴포넌트가 사라질 때 cleanup 함수가 호출된다.
return () => {
console.log('cleanup');
window.removeEventListener('mousemove', onMove)
}
}, []);
[ ]로 지정하면, 컴포넌트가 사라질 때 cleanup 함수가 호출된다.
서블릿
주기함수
init()
doGet() / doPost()
destroy -- cleanup함수와 같은 역할
컴포넌트는 계속 살아있기 때문에 컴포넌트가 나왔다 사라졌다 하게 해야한다.
import React from 'react';
import Test02Sub from './Test02Sub';
import { useState } from 'react';
const Test02 = () => {
const [show, isShow] = useState(false);
const onToggle = () => {
isShow(!show);
}
return (
<div>
<button onClick={ onToggle }>{show ? '숨기기' : '보이기'}</button>
{
show && <Test02Sub/>
}
</div>
);
};
export default Test02;
Test02Sub.jsx - 전체코드
import React from 'react';
import { useEffect } from 'react';
import { useState } from 'react';
const Test02Sub = () => {
const [x, setX] = useState(0);
const [y, setY] = useState(0);
const onMove = (e) => {
//브라우저에서 사용자가 웹페이지에 보여지는 영역을 기준으로 표시
setX(e.clientX);
setY(e.clientY);
}
useEffect(() => {
console.log('useEffect');
window.addEventListener('mousemove', onMove); //이벤트(윈도우 환경에서 이벤트를 발생하는 거 체크한다는 말)
//[]로 지정하면, 컴포넌트가 사라질 때 cleanup 함수가 호출된다.
return () => {
console.log('cleanup');
window.removeEventListener('mousemove', onMove)
}
}, []);
return (
<div>
<h2>마우스 좌표</h2>
<div style={{border: '1px solid #000', width: 400, padding: 30, margin: 15}}>
<h3>X축 : { x }, Y축 : { y }</h3>
</div>
</div>
);
};
export default Test02Sub;
컴포넌트별로 CSS 작성
- 파일명.module.css
- import 참조변수 form './파일명.module.css';
- 개발자 도구에서 보면 '파일명클래스명아무말' 이라고 설정된다
Test08Gallery.jsx
Test08Data.jsx Test08View.jsx
Test08Big.jsx Test08List.jsx
(한 장의 사진은 크게) Test08Item.jsx
Test08Gallery.jsx에서 css를 적용하면 모든 데에 다 적용이 된다.
하지만 개별 jsx에 css를 적용하고싶다면!?
파일명.module.css 이런식으로 하는 것이다.
대신 읽을 때는 import 참조변수 form './파일명.module.css'; 이렇게 읽어야한다.
그리고 개발자 도구에서 보면 '파일명클래스명아무말' 이라고 설정된다.
Test03.css
.box {
width: 400px;
height: 100px;
margin: 20px;
background: hotpink;
border-radius: 25px;
box-sizing: 10px 10px 0 #dcdcdc;
text-align: center;
line-height: 100px;
text-transform: uppercase;
font-size: 40px;
font-weight: 600;
letter-spacing: -1px;
}
Test03.jsx
import React from 'react';
import '../css/Test03.css'
const Test03 = () => {
return (
<div>
<div className='box'>Test</div>
<div>Test</div>
</div>
);
};
export default Test03;
이제 나만의 css를 만들고싶으면 Test03.module.css 이렇게 이름을 지으면 된다.
Test03.module.css
.box {
width: 500px;
height: 80px;
margin: 20px;
background: tomato;
border-radius: 25px;
box-sizing: 10px 10px 0 #dcdcdc;
text-align: center;
line-height: 80px;
text-transform: uppercase;
font-size: 40px;
font-weight: 600;
letter-spacing: -1px;
}
Test03.jsx
import React from 'react';
import '../css/Test03.css'
import myStyle from '../css/Test03.module.css';
const Test03 = () => {
return (
<div>
<div className='box'>Test</div>
<div className={myStyle.box}>Test</div>
</div>
);
};
export default Test03;
Test03.css의 영향은 받지 않는 것을 확인할 수 있다 !!
이런식으로 아무말이나 적히는 거 확인할 수 있다 !!
App.jsx Todos
Test03.jsx Test04.jsx TodoForm TodoList
Test03Sub.jsx TodoItem
App.jsx
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 Test03Sub from './components/Test03Sub';
const App = () => {
return (
<div>
{/*<Test01/>*/}
{/*<Test02/>*/}
<Test03/>
<Test03Sub/>
<Test04/>
</div>
);
};
export default App;
Test03Sub.jsx
import React from 'react';
const Test03Sub = () => {
return (
<div>
<div className='box'>Test</div>
</div>
);
};
export default Test03Sub;
Test04.jsx
import React from 'react';
const Test04 = () => {
return (
<div>
<div className='box'>Test</div>
</div>
);
};
export default Test04;
Test03.jsx
import React from 'react';
import '../css/Test03.css'
import myStyle from '../css/Test03.module.css';
import Test03Sub from './Test03Sub';
const Test03 = () => {
return (
<div>
<div className='box'>Test</div>
<div className={myStyle.box}>Test</div>
<Test03Sub/>
</div>
);
};
export default Test03;
SPA로 한 페이지로 다 들어오기 때문에 여기서 import로 css를 잡지 않아도 알아서 css가 적용되는 것을 볼 수 있다.
'REACT' 카테고리의 다른 글
DAY 77 - React - 데이터 읽기, 쓰기 / 비동기통신(aixos) / useMemo (2024.10.25) (0) | 2024.10.27 |
---|---|
DAY 76 - React HOMEWORK (2024.10.24) (1) | 2024.10.24 |
DAY 75 - React / HOMEWORK (2024.10.23) (3) | 2024.10.23 |
DAY 74 - React (2024.10.22) (2) | 2024.10.22 |
DAY 74 - ES6 (2024.10.22) (0) | 2024.10.22 |