sm 기술 블로그
8강. Update 본문
Update는 Create와 Read를 합치기 때문에 CRUD중에 난이도가 가장 높다.
먼저 기존 코드 에서 전체 추가본을 보겠다.
... 생략 ...
function Update(props){
const [title, setTitle] = useState(props.title);
const [body, setBody] = useState(props.body);
return <article>
<h2>Update</h2>
<form onSubmit={event=>{
event.preventDefault();
const title = event.target.title.value;
const body = event.target.body.value;
props.onUpdate(title,body);
}}>
<p><input type="text" name="title" placeholder="title" value={title} onChange={(event=>{
setTitle(event.target.value);
})}/></p>
<p><textarea name="body" placeholder="body" value={body} onChange={(event=>{
setBody(event.target.value);
})}></textarea></p>
<p><input type="submit" value="Update" /></p>
</form>
</article>
}
... 생략 ...
function App() {
... 생략 ...
let content = null;
let contextControll = null;
... 생략 ...
else if (mode === 'READ'){
let title, body = null;
for(let i=0; i<topics.length; i++){
if(topics[i].id === id){
title = topics[i].title;
body = topics[i].body;
}
}
content = <Article title={title} body={body}></Article>;
contextControll = <li><a href={"/update/" + id} onClick={event=>{
event.preventDefault();
setMode("UPDATE");
}}>Update</a></li>;
}
... 생략 ...
else if (mode === 'UPDATE'){
let title, body = null;
for(let i=0; i<topics.length; i++){
if(topics[i].id === id){
title = topics[i].title;
body = topics[i].body;
}
content = <Update title={title} body={body} onUpdate={(title,body)=>{
const newTopics = [...topics]
const updatedTopic = {id:id, title:title, body:body}
for(let i=0; i<newTopics.length; i++){
if(newTopics[i].id === id){
newTopics[i] = updatedTopic;
break;
}
}
setTopics(newTopics);
setMode('READ');
}}></Update>
}
}
return (
... 생략 ...
<ul>
<li><a href="/create" onClick={event => {
event.preventDefault();
setMode('CREATE');
}}>Create</a></li>
{contextControll}
</ul>
</div>
);
}
export default App;
1. Update 함수형 컴포넌트
function Update(props){
const [title, setTitle] = useState(props.title);
const [body, setBody] = useState(props.body);
return <article>
<h2>Update</h2>
<form onSubmit={event=>{
event.preventDefault();
const title = event.target.title.value;
const body = event.target.body.value;
props.onUpdate(title,body);
}}>
<p><input type="text" name="title" placeholder="title" value={title} onChange={(event=>{
setTitle(event.target.value);
})}/></p>
<p><textarea name="body" placeholder="body" value={body} onChange={(event=>{
setBody(event.target.value);
})}></textarea></p>
<p><input type="submit" value="Update" /></p>
</form>
</article>
}
일단 전에 했던 Create 함수형 컴포넌트와와 매우 유사한 모습을 보인다.
const [title, setTitle] = useState(props.title);
const [body, setBody] = useState(props.body);
먼저 title 과 body를 state화 하였다.
그 이유는 title과 body를 새로 입력받았을 때 기존의 값이 아닌 새로운 값을 props.onUpdate로 넘겨야 하기 때문이다.
그래서 초기값을 props.title (기존에 있던 값)으로 초기화를 하고 새로운 값이 들어오면 setTitle로 값을 바꿔줄것이다.(body도 동일함.)
<p><input type="text" name="title" placeholder="title" value={title} onChange={(event=>{
setTitle(event.target.value);
})}/></p>
<p><textarea name="body" placeholder="body" value={body} onChange={(event=>{
setBody(event.target.value);
})}></textarea></p>
<p><input type="submit" value="Update" /></p>
input과 textarea의 태그가 Create와 다른점이 있다.
value와 onChange가 추가되었다.
value는 기존값을 보여주기 위해 사용된 것이다.
html의 update를 눌렀을 때 나오는 반응으로 제목과 body가 우리가 작성한 topics에 들어오는 값으로 나오는 것을 알 수 있다.
이게 가능한 이유는 title state를 props.title로 초기화 해주었기 때문이다. (body도 동일하다.)
그럼 onChange는 무엇이냐?
input혹은 textarea에 변화가 있다면 실행되는 이벤트이다.
리액트는 기존의 html과 다르게 input과 textarea에 값이 변하면 이벤트가 발생된다.
(기존의 html은 값이 바뀌고 마우스 포인트가 밖으로 나갈때 onChange가 호출됨.)
다음과 같이 ㅁ을 ㄴ을 입력할 때 마다 console.log로 값이 찍힌다.
이 뜻은 변화가 생길 때 마다 onChange가 호출 된다는 것이다.
즉, 변화가 생길 때마다 그 값을 setBody에 넣어준다면 값이 변화된 상태로 있게된다.(title도 동일)
<form onSubmit={event=>{
event.preventDefault();
const title = event.target.title.value;
const body = event.target.body.value;
props.onUpdate(title,body);
}}>
그렇게 변화된 값을 update 버튼을 눌렀을 때 onUpdate라는 곳에 보내주게 된다.
2. else if문 (mode 가 Update일 경우)
else if (mode === 'UPDATE'){
let title, body = null;
for(let i=0; i<topics.length; i++){
if(topics[i].id === id){
title = topics[i].title;
body = topics[i].body;
}
content = <Update title={title} body={body} onUpdate={(title,body)=>{
const newTopics = [...topics]
const updatedTopic = {id:id, title:title, body:body}
for(let i=0; i<newTopics.length; i++){
if(newTopics[i].id === id){
newTopics[i] = updatedTopic;
break;
}
}
setTopics(newTopics);
setMode('READ');
}}></Update>
}
}
먼저 topics중 누가 변화되었는지 알기 위해 id를 반복문을 돌려준다. (다른방법으로도 가능 -> topics[id-1].title 과 같은걸로)
title과 body값을 얻어내고 title과 body를 1번 함수형 컴포넌트에 넘겨준다.
기존의 내용들을 배열화 하여 newTopics에 넣는다.
이게 어떻게 되는지 알고 싶다면 전 7강 Create를 참고하자
https://smhope.tistory.com/508
updateTopic에는 onUpdate 받은 값들을 넣어 줄 것 이다.
(이 값들은 1번 함수형 컴포넌트로 부터 받은 것들 - id 빼고)
다시 배열을 반복문을 돌려 해당 topics 중 어느 topic인지를 찾아낸다.(이것도 역시 다른방법으로 가능)
찾고자 하는 배열 index를 찾으면 거기에 updateTopic을 넣어주고 반복문을 종료한다.
setTopics(newTopics);
setMode('READ');
마지막으로 업데이트가 끝난 newTopics를 기존 topics에 넣어줌으로써 업데이트된 값을 저장해준다.
그리고 mode는 READ로 바꿔주며 읽기 상태로 바꿔준다. (읽기 상태에서는 Update 버튼을 보여주고 Update 에서는 Update버튼을 보여주지 않는 UI로 구현하기 위해서 사용)
3. else if문 (mode 가 READ일 경우)
else if (mode === 'READ'){
let title, body = null;
for(let i=0; i<topics.length; i++){
if(topics[i].id === id){
title = topics[i].title;
body = topics[i].body;
}
}
content = <Article title={title} body={body}></Article>;
contextControll = <li><a href={"/update/" + id} onClick={event=>{
event.preventDefault();
setMode("UPDATE");
}}>Update</a></li>;
}
쓰여진 코드는 다음과 같지만 추가 혹은 변경된 부분은
contextControll = <li><a href={"/update/" + id} onClick={event=>{
event.preventDefault();
setMode("UPDATE");
}}>Update</a></li>;
이부분이다.
READ일 경우에만 Update를 보여주기 위함이다.
다시말해
READ일때는
Update를 보여주고, READ가 아니면
Update를 보여주지 않는다.
4. 하위 컴포넌트
<ul>
<li><a href="/create" onClick={event => {
event.preventDefault();
setMode('CREATE');
}}>Create</a></li>
{contextControll}
</ul>
기존 CREATE와 새로 만든 UPDATE를 좀더 괜찮은 UI로 보기위해 작성한 것이다.
{contextControll}은 READ일 경우에만 보여준다.
https://github.com/denist2322/youtube_react
'리액트' 카테고리의 다른 글
ReactRouter (여러 주소를 사용하기 위한 라이브러리) (0) | 2022.09.01 |
---|---|
9강. Delete (0) | 2022.08.31 |
7강. Create (0) | 2022.08.31 |
6강. state (0) | 2022.08.31 |
5강. 이벤트 (0) | 2022.08.30 |