then 안에 추가navigate(`/members/${res.data.num}`);
function MemberDetail() {
return<>
<h1>회원 정보 자세히 보기</h1>
</>
}
MemberDetail 라우트 경로 추가{path:"/members/:num", element:<MemberDetail/>}
useState 추가const [dto, setDto] = useState({});
useParams 추가{path:"/members/:num", element:<MemberDetail/>} 라우팅 정보에서:num 때문에 {num} 이다const {num} = useParams();
useEffect & axios 추가useEffect(()=>{
axios.get(`/api/v1/members/${num}`)
.then(res => setDto(res.data))
.catch(err => console.log(err));
}, []);
p 요소 추가<p>번호 : <strong>{dto.num}</strong></p>
<p>이름 : <strong>{dto.name}</strong></p>
<p>주소 : <strong>{dto.addr}</strong></p>

NavLink 추가Button 요소로도 가능<th>자세히</th>
<td>
<NavLink to={`/members/${item.num}`}>보기</NavLink>
</td>
<Button as={NavLink} to={`/members/${item.num}`}>보기</Button>
useEffect 에 async 추가(()=>{})(); : 함수를 만들어 바로 호출axios.get(`/api/v1/members/${num}`);(async ()=>{
// promise 가 해결 (서버가 응답) 되면 res 에는 응답 객체가 대입된다
const res = await axios.get(`/api/v1/members/${num}`);
// 상태값 변경하기
setDto(res.data);
})();
➜ 비동기 동작을 하되 순서가 중요할 경우가 존재하기에
순서 보장할 수 있는 axios 사용
const res = await axios.get(`/api/v1/members/${num}`);
const res2 = await axios.get(`/api/v1/members/${num}`);
const res3 = await axios.get(`/api/v1/members/${num}`);
axios 를 try-catch 문 안에 넣기await 이 있으면 해당 함수에는반드시 async 를(async ()=>{
try{
const res = await axios.get(`/api/v1/members/${num}`);
setDto(res.data);
}
catch(err){
console.log(err);
}
})();
➜ 위에서 작성했던 axios.get 코드와 동일한 동작을 한다
onClick 이벤트 요소 추가<Button variant="danger" onClick={handleDelete}>삭제</Button>
hadleDelete 함수 추가const handleDelete = () => {
axios.delete(`/api/v1/members/${dto.num}`)
}
useNavigate 함수 추가const navigate = useNavigate();
hadleDelete 함수에 async & try-catcth 문 추가 및 navigate 사용const handleDelete = async () => {
try{
await axios.delete(`/api/v1/members/${dto.num}`);
alert("삭제 완료");
navigate("/members");
}catch(err){
console.log(err);
}
}
<Button variant="primary" as={NavLink} to={`/members/${dto.num}/edit`}>수정</Button>
function MemberUpdateForm() {
return<>
<h1>회원 수정 양식</h1>
<form>
<div>
<label htmlFor="name">이름</label>
<input type="text" name="name" id="name"/>
</div>
<div>
<label htmlFor="addr">주소</label>
<input type="text" name="addr" id="addr"/>
</div>
<button type="submit">수정</button>
</form>
</>
}
MemberUpdateForm 라우트 경로 추가{path:"/members/:num/edit", element:<MemberUpdateForm/>}
"/members/:num/edit" 에서 num 에 전달된 값 읽어내기const {num} = useParams();
const [dto, setDto] = useState({});
useEffect 함수 추가useEffect(()=>{
axios.get(`/api/v1/members/${num}`)
.then(res=>setDto(res.data));
}, []);
form 에 action 추가 및 input 요소에 value 속성 & onChange 이벤트 추가<form action={`/api/v2/members/${dto.num}`}
<div>
<label htmlFor="name">이름</label>
<input onChange={handleChange} type="text" name="name" id="name" value={dto.name}/>
</div>
<div>
<label htmlFor="addr">주소</label>
<input onChange={handleChange} type="text" name="addr" id="addr" value={dto.addr}/>
</div>
<button type="submit">수정</button>
</form>
handleChange 함수 추가[e.target.name]handleNameChange = (e) => {name:e.target.value}handleAddrChange = (e) => {addr:e.target.value}const handleChange = (e) => {
setDto({
...dto,
[e.target.name]:e.target.value
});
};
form 요소에 onSubmit 이벤트 추가<form action={`/api/v2/members/${dto.num}`} onSubmit={handleSubmit}>
handleSubmit 함수 추가const handleSubmit = async (e) => {
// 폼 제출 막기
e.preventDefault();
// e.target 은 form 요소
// e.target.action 은 form 요소에 작성한 action 속성의 값
// axios.put("요청 url", object) object 를 전달하면 자동으로 json 으로 변경
try{
await axios.put(e.target.action, dto);
alert("수정 완료");
navigate(`/members/${num}`);
}catch(err){
console.log(err);
}
};
useNavigate 함수 추가const navigate = useNavigate();
navigate 를 사용해 페이지 이동navigate(`/members/${num}`)
update 메소드 생성@PutMapping("/members/{num}")
public MemberDto update(@PathVariable int num, @Valid @RequestBody MemberDto dto) {
// 수정할 회원의 번호를 dto 에 넣어준다
dto.setNum(num);
memberService.updateMember(dto);
return dto;
}
useState 함수 추가const [errors, setErrors] = useState({});
catch 문 에 setErrors 함수 사용setErrors(err.response.data.errors);
p 요소 추가<form action={`/api/v2/members/${dto.num}`} onSubmit={handleSubmit}>
<div>
<label className="form-label" htmlFor="name">이름</label>
<input className="form-control" onChange={handleChange} type="text" name="name" id="name" value={dto.name}/>
{errors.name && <p className="form-text text-danger">{errors.name}</p>}
</div>
<div>
<label className="form-label" htmlFor="addr">주소</label>
<input className="form-control" onChange={handleChange} type="text" name="addr" id="addr" value={dto.addr}/>
{errors.addr && <p className="form-text text-danger">{errors.addr}</p>}
</div>
<button className="btn btn-success" type="submit">수정</button>
</form>
navigate 에 object 추가navigate(`/members/${res.data.num}`, {
state:{
message:"새로 추가된 회원 정보"
}
});
useLocation 함수 추가const {state} = useLocation();
Alert 추가{state && <Alert variant="info">{state.message}</Alert>}

navigate 에 object 추가navigate(`/members/${num}`, {
state:{
message:"수정된 회원정보 입니다"
}
});

axios.post(url, object)
axios.put(url, object)
➜ 전달된 obejct 는 자동으로 json 문자열로 변환된 다음 server 에 전송된다
(@RequestBody)
axios.get(url)
axios.delete(url)
function App() {
// React Router v6 에서 제공하는 hook
// 현재 경로에 맞는 자식 route component 를 반환한다
const currentOutlet = useOutlet();
return (
<div className="container pt-4">
<Nav>
<Nav.Item>
<Nav.Link as={NavLink} to="/">HOME</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={NavLink} to="/game">GAME</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={NavLink} to="/study">STUDY</Nav.Link>
</Nav.Item>
</Nav>
{currentOutlet}
</div>
);
}
function Game() {
return <>
<h1>Game 페이지</h1>
</>
}
Game 라우트 경로 추가{path:"/game", element:<Game/>}
.my-bg{
background-color:yellow;
}
css 파일 importimport './css/app.module.css';
className="my-bg"
⭐ 외부 css를 쓰되 특정 컴포넌트에서만 동작하도록 한다
xxx/module.css 로 지으면 반드시 어떤 이름으로 import 해서 사용해야 한다styles 는 obejct 이다// app.module.css 를 import 해서 styles 라는 이름으로 사용하기
import styles from './css/app.module.css';
console.log(styles);
{my-bg: '_my-bg_zergg_1'}
<div class="_my-bg_zergg_1 nav"></div>
{styles["my-bg"} 형식으로 css 코드 사용className={styles["my-bg"]}
.my-bg{
background-color:yellowgreen;
}
import styles from '../css/game.module.css'
function Game() {
return <>
<h1 className={styles["my-bg"]}>Game 페이지</h1>
</>
}
function Study() {
return<>
<h1>Study 페이지</h1>
</>
}
Study 라우트 경로 추가{path:"/study", element:<Study/>}
.my-bg{
background-color:pink;
}
import styles from '../css/study.module.css';
function Study() {
return<>
<h1 className={styles["my-bg"]}>Study 페이지</h1>
</>
}
클래스 제어에 용이
classnames 설치


npm i classnames
<button className="btn btn-primary">버튼1</button>
classnames import 후 적용npm install className 된 모듈을 import 해서 cn 이라는 이름으로 사용하기cn : function typecn() 형식으로 사용import cn from 'classnames';
<button className={cn("btn", "btn-primary")}>버튼2</button>
classArray 상수 생성 후 버튼 추가const classArray = ["btn", "btn-primary"];
<button className={cn(classArray)}>버튼4</button>
classObject 상수 생성 후 버튼 추가const classObject = {"btn":true, "btn-primary":true};v
<button className={cn(classObject)}>버튼6</button>
btn-lg 기본 스타일에 classObject 로 조건부 클래스 함께 적용한 버튼 추가<button className={cn("btn-lg", classObject)}>버튼7</button>
useState 함수 추가const [checked, setChecked] = useState(false);
state 코드 추가<h3>checkbox 의 체크 상태를 state 로 관리</h3>
<label>
<input type="checkbox" checked={checked} /> 체크해 보세요
</label>
input 요소에 onChange 이벤트 추가<input onChange={handleChange} type="checkbox" checked={checked} /> 체크해 보세요
handleChange 함수 추가const handleChange = (e) => {
// 체크박스 체크 여부를 알아내서
const isChecked = e.target.checked;
// 상태값을 반영한다
setChecked(isChecked);
};
p 요소 추가<p className={cn({"bg-info":checked})}>하늘색 표시</p>


value 코드 추가<h3>checkbox 의 value 도 같이 사용해 보기</h3>
<label>
<input type="checkbox" value="bg-info"/> 하늘색 배경
</label>
<label>
<input type="checkbox" value="text-danger"/> 빨간색 글자
</label>
useState 함수 추가const [messageStyle, setMessageStyle] = useState({
"bg-info":false,
"text-danger":false
});
input 요소에 onChange 이벤트 추가<input onChange={handleChange2} type="checkbox" value="bg-info"/> 하늘색 배경
<input onChange={handleChange2} type="checkbox" value="text-danger"/> 빨간색 글자
handleChange2 함수 추가const handleChange2 = (e) => {
const value = e.target.value; // checkbox 의 value 값 "bg-info" or "text-danger"
const isChecked = e.target.checked; // 체크 여부 true or false
// 상태값 변경하기
setMessageStyle({
...messageStyle,
[value]:isChecked
});
};
➜ e.target 도 object 이기에 단축시키는 코드 가능
const value = e.target.value;
const isChecked = e.target.checked;
⭣
const {value, isChecked} = e.target;
<p className={cn(messageStyle)}>표시 확인</p>
