리액트에서 레이아웃 만들 때 쓰는 JSX 문법 3개
1. class 대신에 className
2. 변수를 html 에 넣고 싶을 땐 { 중괄호 }
3. style 넣고 싶을땐
4. 중요한 데이터는 변수말고 state에 담습니다
let [name, setName] = useState("김성우");
라고하면, name 이라는 변수에 "김성우"를 임시 저장하고
setName 이라는 인자로 변수명을 변경할 수 있다.
라우터를 배우기 전에 , 블로그 만들기를 해보았는데
코드는 다음과 같다.
// 'logo'가 사용되지 않을 경우 아래 줄을 제거하세요.
import logo from "./logo.svg";
import "./App.css";
import { useState } from "react";
const PostCategory = ({
id,
title,
content,
publishDate,
likes,
onLikeClick,
onToggleModal,
onDeleteClick,
onEditClick,
}) => (
<div className="col p-4 d-flex flex-column position-static list">
<strong className="d-inline-block mb-2 text-success title">
게시글 번호 {id}
</strong>
<h3 className="mb-0 post-title">{title}</h3>
<div className="mb-3 text-muted post-date">{publishDate}</div>
<p className="mb-4 post-content">{content}</p>
<p className="mb-5">
<button className="btn btn-primary" onClick={onLikeClick}>
👍
</button>
좋아요 개수: {likes}{" "}
</p>
<button
className="btn btn-secondary mb-2"
onClick={() => onToggleModal(id)} // 상세보기 버튼 클릭 시 onToggleModal 함수 호출
>
게시글 상세보기
</button>
<div className="d-flex flex-column">
<div className="row">
<button
className="btn btn-warning col m-2"
onClick={() => onEditClick(id)}
>
수정
</button>
<button
className="btn btn-danger col m-2"
onClick={() => onDeleteClick(id)}
>
삭제
</button>
</div>
</div>
</div>
);
function App() {
const [posts, setPosts] = useState([
{
id: 1,
title: "남자 코트 추천 해드립니다!",
content: "이 코트는 모의 회사에서 개발한 코트입니다.",
publishDate: "2023-01-01",
likes: 0,
},
{
id: 2,
title: "강남 우동 맛집 소개!",
content: "이 우동집은 모의 회사에서 개발한 우동집입니다.",
publishDate: "2023-01-02",
likes: 0,
},
{
id: 3,
title: "파이썬 독학하는 방법좀 알려주세요",
content: "파이썬을 독학하려면 어떻게 해야할까요? ",
publishDate: "2023-01-03",
likes: 0,
},
]);
const getCurrentDate = () => {
const currentDate = new Date();
const year = currentDate.getFullYear();
const month = String(currentDate.getMonth() + 1).padStart(2, "0");
const day = String(currentDate.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
};
const [newPost, setNewPost] = useState({
id: posts.length + 1, // Generating a new id for the new post
title: "",
content: "",
publishDate: getCurrentDate(), // Assuming you want to set the current date
likes: 0,
});
const handleInputChange = (e) => {
const { name, value } = e.target;
setNewPost((prevPost) => ({
...prevPost,
[name]: value,
}));
};
const addNewPost = () => {
setPosts((prevPosts) => [...prevPosts, newPost]);
setNewPost({
id: posts.length + 2,
title: "",
content: "",
publishDate: getCurrentDate(),
likes: 0,
});
};
const [isModalVisible, setModalVisibility] = useState(false);
const [modalIndex, setModalIndex] = useState(0);
// let [changeValue, setChangeValue] = useState("");
const changeTitle = (index) => {
const updatedPosts = [...posts];
updatedPosts[modalIndex].title += " 새로운";
setPosts(updatedPosts);
};
const toggleModal = (index) => {
setModalVisibility(!isModalVisible);
setModalIndex(index);
};
const incrementLikes = (index) => {
const updatedPosts = [...posts];
updatedPosts[index].likes += 1;
setPosts(updatedPosts);
};
const deletePost = (postId) => {
const updatedPosts = posts.filter((post) => post.id !== postId);
setPosts(updatedPosts);
};
return (
<div className="App d-flex flex-column align-items-center">
<div className="black-nav main-head-height d-flex align-items-center justify-content-center">
<img
src={logo}
alt="ReactBlog Logo"
className="logo-img"
style={{ width: "50px", height: "50px", marginRight: "10px" }}
/>
<h4>ReactBlog</h4>
</div>
{posts.map((post, index) => (
<div className="list" key={post.id} style={{ width: "65%" }}>
<PostCategory
id={post.id}
title={post.title}
content={post.content}
publishDate={post.publishDate}
likes={post.likes}
onLikeClick={() => incrementLikes(index)}
onToggleModal={() => toggleModal(index)}
onDeleteClick={() => deletePost(post.id)}
/>
</div>
))}
{isModalVisible === true ? (
<Modal
isVisible={isModalVisible}
title={posts[modalIndex].title}
postDate={posts[modalIndex].publishDate}
postContent={posts[modalIndex].content}
skyblue={"skyblue"}
changeTitle={() => changeTitle(modalIndex)} // changeTitle 함수를 props로 내려줌
toggleModal={() => toggleModal(modalIndex)} // toggleModal 함수를 props로 내려줌
modalIndex={modalIndex}
></Modal>
) : null}
<div
className="list text-center"
style={{ width: "65%", margin: "0 auto" }}
>
{/* ... (이전 코드 유지) */}
{/* 새로운 게시글 입력 폼 */}
<div className="mb-3">
<label htmlFor="postTitle" className="form-label">
제목
</label>
<input
type="text"
className="form-control"
id="postTitle"
name="title"
value={newPost.title}
onChange={handleInputChange}
/>
</div>
<div className="mb-3">
<label htmlFor="postContent" className="form-label">
내용
</label>
<textarea
className="form-control"
id="postContent"
name="content"
rows="3"
value={newPost.content}
onChange={handleInputChange}
></textarea>
</div>
<button className="btn btn-primary mb-5" onClick={addNewPost}>
새로운 게시글 추가
</button>
</div>
{/* <input
className="m-5"
onChange={(e) => {
setChangeValue(e.target.value);
console.log(e.target.value);
}}
></input> */}
<div className="mt-5 black-nav main-head-height d-flex flex-column align-items-center justify-content-center">
<h4>ReactBlog</h4>
</div>
</div>
);
}
// modal 컴포넌트 만들기
function Modal(props) {
if (props.isVisible === true) {
const modalTitle = props.title || "제목이 없습니다.";
const postDate = props.postDate || "날짜가 없습니다.";
const postContent = props.postContent || "상세내용이 없습니다.";
return (
<div
className="modal fade show"
style={{ display: "block" }}
tabIndex="-1"
role="dialog"
>
<div
className="modal-dialog text-center modal-dialog-centered"
role="document"
>
<div className="modal-content rounded-5 shadow p-4">
<div className="mb-3">
<div className="d-block">
<h1 className="modal-title fs-5">{modalTitle}</h1>
</div>
<div className="d-block">
<p className="modal-date ml-auto">{postDate}</p>
</div>
</div>
<div className="modal-body py-0 text-center">
<p>{postContent}</p>
</div>
<div className="modal-footer flex-column align-items-stretch w-100 gap-2 pb-3 border-top-0">
<button
type="button"
className="btn btn-lg btn-primary"
onClick={props.changeTitle}
>
제목 변경
</button>
<button
type="button"
className="btn btn-lg btn-secondary"
onClick={props.toggleModal}
data-bs-dismiss="modal"
>
Close
</button>
</div>
</div>
</div>
</div>
);
} else {
return null;
}
}
export default App;
여기서 PostCategory 라는 변수에 화살표 함수를 이용해서, html 을 return 해주었다.
const PostCategory = ({
id,
title,
content,
publishDate,
likes,
onLikeClick,
onToggleModal,
onDeleteClick,
onEditClick,
}) => (
<div className="col p-4 d-flex flex-column position-static list">
<strong className="d-inline-block mb-2 text-success title">
게시글 번호 {id}
</strong>
<h3 className="mb-0 post-title">{title}</h3>
<div className="mb-3 text-muted post-date">{publishDate}</div>
<p className="mb-4 post-content">{content}</p>
<p className="mb-5">
<button className="btn btn-primary" onClick={onLikeClick}>
👍
</button>
좋아요 개수: {likes}{" "}
</p>
<button
className="btn btn-secondary mb-2"
onClick={() => onToggleModal(id)} // 상세보기 버튼 클릭 시 onToggleModal 함수 호출
>
게시글 상세보기
</button>
<div className="d-flex flex-column">
<div className="row">
<button
className="btn btn-warning col m-2"
onClick={() => onEditClick(id)}
>
수정
</button>
<button
className="btn btn-danger col m-2"
onClick={() => onDeleteClick(id)}
>
삭제
</button>
</div>
</div>
</div>
);
이렇게 넣어보았다.
{posts.map((post, index) => (
<div className="list" key={post.id} style={{ width: "65%" }}>
<PostCategory
id={post.id}
title={post.title}
content={post.content}
publishDate={post.publishDate}
likes={post.likes}
onLikeClick={() => incrementLikes(index)}
onToggleModal={() => toggleModal(index)}
onDeleteClick={() => deletePost(post.id)}
/>
</div>
))}
리액트 문법에서, PostCategory 를
<PostCategory />로 넣어줬고 이 친구는
안에 있는 id, title, content, publishDate, likes 등등을 리턴해준다.
5. useState 를 이용해서, 좋아요 개수 나타내보기
현재 likes 라는 변수는, 딕셔너리 형식으로 , useState 를 이용하여 저장해두었다.
const [posts, setPosts] = useState([
{
id: 1,
title: "남자 코트 추천 해드립니다!",
content: "이 코트는 모의 회사에서 개발한 코트입니다.",
publishDate: "2023-01-01",
likes: 0,
},
{
id: 2,
title: "강남 우동 맛집 소개!",
content: "이 우동집은 모의 회사에서 개발한 우동집입니다.",
publishDate: "2023-01-02",
likes: 0,
},
{
id: 3,
title: "파이썬 독학하는 방법좀 알려주세요",
content: "파이썬을 독학하려면 어떻게 해야할까요? ",
publishDate: "2023-01-03",
likes: 0,
},
]);
현재는, posts 라는 변수에 다음을 저장해두었지만,
setPosts 라는 갱신 함수를 통해서 , 변수를 갱신해줄 수 있다.
<p className="mb-5">
<button className="btn btn-primary" onClick={onLikeClick}>
👍
</button>
좋아요 개수: {likes}{" "}
</p>
버튼에 onClick={onLikeClick} 을 추가해주었다.
const incrementLikes = (index) => {
const updatedPosts = [...posts];
updatedPosts[index].likes += 1;
setPosts(updatedPosts);
};
[...posts] 는 배열의 전개 연산자(Spread Operator)를 사용한 문법입니다.
기존의 posts 배열을 복사하여 새로운 배열 updatedPosts를 생성합니다.
이렇게 복사를 하는 이유는 React에서 상태를 직접적으로 수정하지 않고, 새로운 상태를 만들어야 하기 때문입니다.
새로운 배열을 만들고 나서 해당 배열을 수정한 후에
setPosts 함수를 사용하여 상태를 업데이트합니다.
이 방식은 불변성(Immutability)을 유지하는 데 도움이 되며, React에서는 상태를 불변하게 유지하는 것이 중요합니다.
이렇게 함으로써 React는 상태의 변화를 감지하고 필요한 경우에만 리렌더링을 수행할 수 있습니다.
'Library&Framework > React' 카테고리의 다른 글
리액트 리덕스를 활용한 마이페이지 리팩토링: 코드 개선을 통한 유지보수성 및 재사용성 향상 (0) | 2024.06.30 |
---|---|
[리액트 강의 복습 03] 리액트에서 map 을 이용한 게시글 리스트 보기 , 게시글 작성하기 (1) | 2024.01.04 |
[리액트 강의 복습 02] 리액트 모달창 UI 만들기 (0) | 2024.01.04 |
React 를 쓰는 이유? (0) | 2024.01.03 |