- modal 창 닫기
- NewPoost 컴포넌트에 입력한 본문과 저자이름 데이터를 가져와야함.
- 목록에 post 추가하기 (동적으로 출력되게)
기본적으로 form을 전송하면 Submit 이벤트가 트리거되고, 그럼 브라우저는 자동으로 HTTP 요청을 만들어 전송하는데 위에서 말한것처럼 이 동작을 안하려고함.
이 리액트 앱을 서비스하는 서버로 HTTP 요청을 보내면 페이지가 다시 로딩될 텐데 그 요청을 처리할 서버 쪽 코드가 현재는 없음. 리액트는 서버가 아니라 브라우저에서 동작하는 프런트엔드 라이브러리라서 그런 요청을 처리할 수 없음.
그래서 submit 이벤트에서 내장 메서드인 'preventDefault()'
호출 : 브라우저가 자동으로 HTTP 요청을 만들어 전송하는 걸 막음
그런데 이 작업을 하기 전에 우선 입력값을 관리해주는 PostList.jsx
에서 하위 스크립트이자 현재 작업할 NewPost.jsx
로 코드를 옮겨올 것임.
그러면 폼을 전송하더라도 전송이 안될 것이고,
이후 전송을 했으므로 업데이트가 됐을 것이므로
객체에 새롭게 업데이트된 본문과 저자이름 데이터를 담음.
그리고 폼전송을 해서 업데이트 된 객체가 담겼는지 확인을 종종해야함. console.log 를 찎어봐서 확인하기.
cf. 중간에
props.onAddPost(postData);
props.onCancel();
이 프로퍼티 둘은 함수를 값으로 받는 프로퍼티이기 때문에 호출이 가능함.
✍ NewPost.jsx
import { useState } from "react";
import classes from "./NewPost.module.css";
function NewPost(props) {
const [enteredBody, setEnteredBody] = useState("");
const [enteredAuthor, setEnteredAuthor] = useState("");
function bodyChangeHandler(event) {
setEnteredBody(event.target.value);
}
function authorChangeHandler(event) {
setEnteredAuthor(event.target.value);
}
function submitHandler(event) {
event.preventDefault();
const postData = {
body: enteredBody,
author: enteredAuthor,
};
props.onAddPost(postData);
props.onCancel();
}
return (
<form className={classes.form} onSubmit={submitHandler}>
<p>
<label htmlFor="body">Text</label>
<textarea id="body" required rows={3} onChange={bodyChangeHandler} />
</p>
<p>
<label htmlFor="name">Your name</label>
<input type="text" id="name" required onChange={authorChangeHandler} />
</p>
<p className={classes.actions}>
<button type="button" onClick={props.onCancel}>
Cancel
</button>
<button>Sumbit</button>
</p>
</form>
);
}
export default NewPost;
이전 상태를 바탕으로 새로운 상태를 만들 때는 함수 형태를 써서 상태를 업데이트 하자!
이 아래NewPost.jsx
부분이 중요한데setPosts 함수
의 매개변수로 화살표 함수를 줬다. 그리고existingPosts
과posts
는 같은 이전 상태값으로 쓰였다. 그러니까 변수명만 다를뿐, 똑같은 값이 들어있다.리액트 훅인 useState 에서 두번쨰 인자로 들어온 함수는 상태를 업데이트 해주는 함수이고, 이 함수의 매개변수는 이전상태값이다. 즉 ,
posts
이다.
setPosts 의 매개변수로 화살표 함수로 변경헀음.
이유 : 새로운 상태 값이 이전 상태 값을 바탕으로 한 것이기 떄문에.
왜냐하면 왜냐하면 리액트 내부에서는 상태 갱신 함수를 곧바로 실행하는 게 아니기 때문. 단지 상태 갱신을 예약해 둘 뿐.
그럼 여러 업데이트가 서로 얽혀서 일어날 때 잘못된 상태 갱신을 할 수도 있음. 그래서 리액트가 상태를 가져올떄 그 즉시 이전상태를 가져와 새 상태로 업데이트 하는것임.
이전 상태가 자동으로 들어올 테니 이를 받아 새로운 상태를 만들고 값으로 반환하면 된다.
즉, 안전하게 함수 형태로 상태를 업데이트 하자!
// 이렇게
function addPostHandler(postData) {
setPosts((existingPosts) => [postData, ...existingPosts]);
}
✍ NewPost.jsx
import { useState } from "react";
import Post from "./Post";
import NewPost from "./NewPost";
import Modal from "./Modal";
import classes from "./PostList.module.css";
function PostList({ isPosting, onStopPosting }) {
const [posts, setPosts] = useState([]);
function addPostHandler(postData) {
setPosts((existingPosts) => [postData, ...existingPosts]);
}
return (
<>
{isPosting && (
<Modal onClose={onStopPosting}>
<NewPost onCancel={onStopPosting} onAddPost={addPostHandler} />
</Modal>
)}
<ul className={classes.posts}>
<Post author="Manel" body="the second props pratice!" />
</ul>
</>
);
}
export default PostList;