78일차 내용 정리

채공부·2025년 9월 11일

axios

회원 정보 자세히 보기

  • MemberForm.jsx 에 폼 전송 후 추가한 회원의 정보 자세히 보기로 이동하는 코드 then 안에 추가
navigate(`/members/${res.data.num}`);
  • pages 폴더 안에 MemberDetail.jsx 생성
function MemberDetail() {
    return<>
        <h1>회원 정보 자세히 보기</h1>

    </>
}
  • index.jsx 에 MemberDetail 라우트 경로 추가
{path:"/members/:num", element:<MemberDetail/>}
  • MemberDetail 에 useState 추가
    • ui 에 출력할 회원 정보를 state 값으로 관리
const [dto, setDto] = useState({});
  • MemberDetail 에 useParams 추가
    • 경로 변수에 있는 값을 읽어내기
    • {path:"/members/:num", element:<MemberDetail/>} 라우팅 정보에서
      :num 때문에 {num} 이다
const {num} = useParams();
  • MemberDetail 에 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>

  • Member.jsx 에 해당 회원의 자세히 보기로 이동하는 NavLink 추가
    • React Bootstrap 에서 제공해주는 Button 요소로도 가능
<th>자세히</th>
<td>
	<NavLink to={`/members/${item.num}`}>보기</NavLink>
</td>
<Button as={NavLink} to={`/members/${item.num}`}>보기</Button>
  • MemberDetail.jsx 에 useEffectasync 추가
    • 비동기 동작하는 함수를 만들어서 바로 호출하기
    • (()=>{})(); : 함수를 만들어 바로 호출
    • 이 promise 가 해결 (응답)될 때까지 기다리기 라는 의미
      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}`);
  • axiostry-catch 문 안에 넣기
    • 함수 안에 await 이 있으면 해당 함수에는반드시 async
      붙여 주어야 한다
(async ()=>{
	try{
		const res = await axios.get(`/api/v1/members/${num}`);
		setDto(res.data);
	}
	catch(err){
		console.log(err);           
	}
})();

➜ 위에서 작성했던 axios.get 코드와 동일한 동작을 한다

회원 정보 삭제

  • MemberDetail.jsx 에 삭제 버튼 & 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 사용
    • 함수 내부에 await 이 있기 때문에 async 예약어를 함수에 붙여준다
    • axios 를 이용해서 삭제 요청을 한다
const handleDelete = async () => {
	try{
		await axios.delete(`/api/v1/members/${dto.num}`);
		alert("삭제 완료");
		navigate("/members");
	}catch(err){
		console.log(err);            
	}
}

회원 정보 수정

  • MemberDetail.jsx 에 수정 버튼 추가
<Button variant="primary" as={NavLink} to={`/members/${dto.num}/edit`}>수정</Button>
  • pages 폴더 안에 MemberUpdateForm.jsx 생성
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>
    </>
}
  • index.jsx 에 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));
}, []);
  • formaction 추가 및 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 함수 추가
    • input 요소에 입력한 값을 이용해서 상태값을 반영하기 위한 함수
    • [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 함수 추가
    • form 에 submit 이벤트가 발생했을 때 실행할 함수
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}`)
  • RestController2 에 update 메소드 생성
    • 회원 정보 전체 수정 요청 처리
@PutMapping("/members/{num}")
public MemberDto update(@PathVariable int num, @Valid @RequestBody MemberDto dto) {
	// 수정할 회원의 번호를 dto 에 넣어준다
	dto.setNum(num);
	memberService.updateMember(dto);
	return dto;
}

에러 메세지

  • MemberForm.jsx 에 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>
  • MemberForm.jsx 에 navigateobject 추가
navigate(`/members/${res.data.num}`, {
	state:{
		message:"새로 추가된 회원 정보"
	}
});
  • MemberDetail.jsx 에 useLocation 함수 추가
    • location 은 object 인데 location 객체가 가지고 있는 정보를 확인할 수 있다
    • location 객체에서 state 정보만 얻어낸다 (null 일 수도 있다)
const {state} = useLocation();
  • 조건부로 메세지를 출력하는 Alert 추가
{state && <Alert variant="info">{state.message}</Alert>}

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

axios.post(url, object)
axios.put(url, object)
➜ 전달된 obejct 는 자동으로 json 문자열로 변환된 다음 server 에 전송된다
  (@RequestBody)

axios.get(url)
axios.delete(url)

css

  • App.jsx 에 링크 추가
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>
    );
}
  • Game.jsx 생성
function Game() {
    return <>
       <h1>Game 페이지</h1>     
    </>
}
  • index.jsx 에 Game 라우트 경로 추가
{path:"/game", element:<Game/>}
  • css 폴더 생성 후 app.module.css 생성
.my-bg{
    background-color:yellow;
}
  • App.jsx 에 css 파일 import
import './css/app.module.css';
  • css 적용
className="my-bg"

⭐ 외부 css를 쓰되 특정 컴포넌트에서만 동작하도록 한다

  • app.module.css 를 import 해서 styles 라는 이름으로 사용하기
    • css 파일명을 xxx/module.css 로 지으면 반드시 어떤 이름으로 import 해서 사용해야 한다
    • 여기서 stylesobejct 이다
// app.module.css 를 import 해서 styles 라는 이름으로 사용하기
import styles from './css/app.module.css';
  • styles object 의 구조 확인
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"]}
  • game.module.css 생성
.my-bg{
    background-color:yellowgreen;
}
  • Game.jsx 에 css 파일 import 후 적용
import styles from '../css/game.module.css'

function Game() {
    return <>
       <h1 className={styles["my-bg"]}>Game 페이지</h1>     
    </>
}
  • Study.jsx 생성
function Study() {
    return<>
        <h1>Study 페이지</h1>
    </>
}
  • index.jsx 에 Study 라우트 경로 추가
{path:"/study", element:<Study/>}
  • study.module.css 생성
.my-bg{
    background-color:pink;
}
  • Study.jsx 에 css 파일 import 후 적용
import styles from '../css/study.module.css';

function Study() {
    return<>
        <h1 className={styles["my-bg"]}>Study 페이지</h1>
    </>
}

classnames 사용법 (조건부 클래스 적용)

클래스 제어에 용이

classnames 설치

  1. npm 에서 classnames 검색

  1. install 코드 복사

  1. VS CODE 에서 Terminal 실행 후 해당 코드 붙여넣기
npm i classnames
  • Home.jsx 에 버튼 추가
 <button className="btn btn-primary">버튼1</button>
  • classnames import 후 적용
    • npm install className 된 모듈을 import 해서 cn 이라는 이름으로 사용하기
    • cn : function type
    • cn() 형식으로 사용
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 함수 추가
    • 체크박스의 체크 상태는 boolean type 으로 관리할 수 있다
const [checked, setChecked] = useState(false);
  • checkbox 상태 관리하는 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>

  • checkbox 상태 관리하는 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.targetobject 이기에 단축시키는 코드 가능

const value = e.target.value;
const isChecked = e.target.checked;const {value, isChecked} = e.target;
  • 적용 상태 확인하는 p 요소 추가
<p className={cn(messageStyle)}>표시 확인</p>

profile
학원 공부 내용 정리

0개의 댓글