대부분의 애플리케이션에는 CREATE | READ | UPDATE | DELETE 에 의해 동작되고 지금까지 READ 에 대해서 알아봤다면 이번에는 CREATE, UPDATE, DELETE 에 대한 부분이다.
CREATE
function App() {
// .. 생략 ..
return (
<div>
<Header title="REACT" onChangeMode={(event) => {
setMode('WELCOM');
}}></Header>
<Nav topics={topics} onChangeMode={(_id) => {
setMode('READ');
setId(_id);
}}></Nav>
{content}
<a href="/create" onClick={event => {
event.preventDefault();
setMode('CREATE');
}}>Create</a>
</div>
);
}
먼저 create 라는 링크를 App 컴포넌트에 추가 한다. 링크를 클릭했을 때 모드가 바뀔 수 있도록 setMode 로 상태도 변경시킨다. 이제 추가한 링크를 클릭해보면 아무것도 출력되지 않는다. 현재 mode 조건문에 CREATE 조건이 없기 때문이며 추가하도록 한다.
if (mode === 'WELCOME') {
// 생략
} else if (mode === 'READ') {
// 생략
} else if (mode === 'CREATE') {
content = <Create></Create>;
}
일단 mode 조건에 CREATE 조건을 추가하고 Create 컴포넌트로 만들기 위해 컴포넌트 태그를 입력했다.
function Create(props)
{
return <article>
<h2>Create</h2>
<form>
<p><input type="text" name="title" placeholder="title" /></p>
<p><textarea name="body" placeholder="body"></textarea></p>
<p><input type="submit" value="Create" /></p>
</form>
</article>
}
그리고 이렇게 Create 컴포넌트를 작성했다. form 태그 안에 title, body 값을 입력 받는 부분을 추가하고 그 값을 전송하도록 submit 을 추가한다.
if (mode === 'WELCOME') {
// 생략
} else if (mode === 'READ') {
// 생략
} else if (mode === 'CREATE') {
content = <Create onCreate={(_title, _body) => {
}}></Create>;
}
다음으로 mode 조건문으로 다시 돌아와 생성 버튼을 클릭했을 때 후속 작업을 할 수 있는 인터페이스를 제공하기 위해 콜백 함수를 추가한다.
<form onSubmit={event => {
event.preventDefault();
const title = event.target.title.value;
const body = event.target.body.value;
props.onCreate(title, body);
}}>
form 태그에는 onSubmit 이라는 이벤트를 부여하고 submit 을 했을 때 리로드 되지 않도록 방지하고 title 과 body 의 값을 얻어내기 위해 event 객체의 target 을 통해서 각각의 값을 가져와 onCreate 함수를 실행하기 위해 각각의 파라미터에 넣어준다.
여기까지는 사용자가 create 링크를 클릭해 title 과 body 를 입력받을 수 있는 화면을 출력하고 입력한 값을 전송하는 부분까지다. 이제 전송받은 값을 사용자에게 제공하도록 해보겠다.
function App() {
const [mode, setMode] = useState('WELCOME');
const [id, setId] = useState(null);
const [topics, setTopics] = useState([ // 1. topics 를 읽고 쓸 수 있도록 상태로 변경
{id: 1, title: 'html', body: 'html is ...'},
{id: 2, title: 'css', body: 'css is ...'},
{id: 3, title: 'javascript', body: 'javascript is ...'}
]);
const [nextId, setNextId] = useState(4); // 2. topics 의 다음 id 값을 설정. topics 의 마지막 id 값이 3 이므로 다음에 들어갈 4 로 초기화.
let content = null;
if (mode === 'WELCOME') {
// 생략
} else if (mode === 'READ') {
// 생략
} else if (mode === 'CREATE') {
content = <Create onCreate={(_title, _body) => {
const newTopic = {id: nextId, title: _title, body: _body}; // 3. topics 에 들어갈 객체
const newTopics = [...topics]; // 4. topics 를 복제해 newTopics 를 만든다.
newTopics.push(newTopic); // 5. 복제한 newTopics 에 newTopic 을 추가하고
setTopics(newTopics); // 6. 새로운 newTopics 를 topics 의 상태로 변경한다.
setMode('READ'); // 7. Create 후 상세 보기로 넘어가도록 mode 상태를 READ 값으로 변경한다.
setId(nextId); // 8. id 는 nextId 로 변경 하고
setNextId(nextId + 1); // 9. nextId 는 거기에 + 1
}}></Create>;
}
// 생략
}
먼저, 1. topics 를 읽고 쓸 수 있도록 상태로 변경고 topics 마지막 원소의 다음 id 값을 설정하기 위해 2. nextId 라는 상태를 선언하고 topics 의 마지막 id 값이 3 이므로 다음에 들어갈 4 로 초기화했다. 그 다음 3. topics 에 들어갈 newTopic 객체를 만들었다. 그리고 이 객체를 topics 에 넣기 위해서 topics.push(newTopic); setTopics(topics); 해봤더니 아무 반응도 일어나지 않는다.
여기서 잠깐, 객체 혹은 배열의 경우 원래의 데이터를 변경하지 않고 복사해 복사한 데이터를 변경하여 설정한다.
React 에서는 객체나 배열 상태의 경우 불변성을 지켜주어야만 컴포넌트에서 상태가 업데이트가 됐음을 감지 할 수 있고 때문이라고 한다.
그러면 이제 4. topics 를 복사해 newTopics 를 만들고 5. 복제한 newTopics 에 newTopic 을 추가한다. 그 다음 6. 새로운 newTopics 를 topics 의 상태로 변경하고 7. Create 후 상세 보기로 넘어가도록 mode 상태를 READ 값으로 변경한다. 8. id 는 추가한 nextId 로 변경 하고 다음 글을 볼 수 있도록 9. nextId 는 거기에 + 1 하면 CREATE 과정이 마무리 된다.
UPDATE
Create 와 비슷하다. 다른 점에 대해서만 짚어보도록 하겠다.
function Update(props)
{
// title 과 body 속성으로 상태값을 만들어 입력될 때마다 값이 설정되게 한다.
const [title, setTitle] = useState(props.title);
const [body, setBody] = useState(props.body);
return <article>
<h2>Update</h2>
<form onSubmit={event => {
event.preventDefault();
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>
}
먼저 Update 컴포넌트를 생성한다. props 의 title 과 body 를 속성으로 만들고 값이 변경될 때마다 설정되도록 input 과 textarea 에 onChange 이벤트를 주어 각각의 상태값을 설정했다.
// ... 생략
} else if (mode === 'UPDATE') {
let title, body = null;
topics.map(x => {
if (x.id === id) {
title = x.title;
body = x.body;
}
});
content = <Update title={title} body={body} onUpdate={(_title, _body) => {
const updatedTopic = {id: id, title: _title, body: _body};
const newTopics = [...topics];
newTopics.map((topic, index) => {
if (topic.id === id) {
newTopics[index] = updatedTopic;
}
});
setTopics(newTopics);
setMode('READ');
}}></Update>;
}
// ... 생략
App 컴포넌트에서 먼저
let contextControl = null; // 페이지 이동 링크
이렇게 변수를 설정해 WELCOME 과 READ 모드에서 사용하는 링크를 설정했다. 그 다음 mode 가 UPDATE 인 조건문을 만들고 여기서는 topics 의 특정 index 의 데이터를 변경할 수 있도록 설정했다.
DELETE
<li><button type="button" onClick={event => {
const newTopics = [];
topics.map(topic => {
if (topic.id !== id) newTopics.push(topic);
});
setTopics(newTopics);
setMode('WELCOME');
}}>Delete</button></li>
이제 마지막 단계! 정말 간단했다. READ mode 에서 Delete 버튼을 추가하고 이벤트 발생시 topics 에서 해당 id 요소와 같지 않은 것들만 newTopics 에 담아 topics 를 설정 한 후 해당 글은 삭제했으니 WELCOME mode 로 상태를 변경해주면 이 강의의 진도가 끝나게 된다.
마무리
React 한 번 해보고 싶다며 생각만 한지 참 오랜 시간이 지난 것 같다. 어떻게 시작하면 좋을지 고민만 있었는데 생활코딩에서 개정된 수업이 짧은 호흡으로 올라와 수업을 들어볼 수 있었고 들으며 충분히 React 에 대한 흥미를 가질 수 있는 계기가 됐다. 그래서 이젠 "나 React 뭔지 알아!" 정도는 어디가서 말 할 수 있는 정도가 됐다고 할 수 있겠다. 하지만 아직 실무에 적용해보기에는 좀 더 공부해야 할 것 같고 그건 아래 링크에 들어가면 심화 내용이 있으니 React 에 대해 좀 더 알아봐야 겠다.
'Develop > React' 카테고리의 다른 글
[ReactJS] 에러 "ReactDOM.render is no longer supported in React 18" (0) | 2022.08.07 |
---|---|
"생활코딩 | React 2022년 개정판" 을 공부하며.. 2탄 (0) | 2022.03.27 |
"생활코딩 | React 2022년 개정판" 을 공부하며.. 1탄 (0) | 2022.03.27 |
댓글