---
title: React에서 Parse를 사용한 기본 CRUD 구현 가이드
slug: docs-kr/react/data-objects/react-crud-tutorial
description: React 애플리케이션에서 Parse 서버를 활용하여 기본 CRUD(Create, Read, Update, Delete) 작업을 수행하는 방법을 학습합니다.
image: https://www.back4app.com/images/logo-social.png
createdAt: 2024-03-12T14:26:46.555Z
---

# 리액트 CRUD 튜토리얼

## 소개

Parse에 데이터를 저장하는 것은 <font color="#2166ae">`Parse.Object`</font> 클래스를 중심으로 구성됩니다. 각 <font color="#2166ae">`Parse.Object`</font>는 JSON 호환 데이터의 키-값 쌍을 포함합니다. 이 데이터는 스키마가 없으므로 각 <font color="#2166ae">`Parse.Object`</font>에 어떤 키가 존재하는지 미리 지정할 필요가 없습니다. 원하는 키-값 쌍을 설정하면, 우리의 백엔드가 이를 저장합니다.

또한 애플리케이션의 필요에 따라 데이터 유형을 지정하고 <font color="#2166ae">`숫자`</font>, <font color="#2166ae">`부울`</font>, <font color="#2166ae">`문자열`</font>, <font color="#2166ae">`날짜 및 시간`</font>, <font color="#2166ae">`목록`</font>, <font color="#2166ae">`지리 포인터`</font>, 그리고 <font color="#2166ae">`객체`</font>, 저장하기 전에 JSON으로 인코딩합니다. Parse는 또한 <font color="#2166ae">`포인터`</font> 및 <font color="#2166ae">`관계`</font>와 같은 유형을 사용하여 관계형 데이터를 저장하고 쿼리하는 것을 지원합니다.

이 가이드에서는 CRUD 예제 앱을 통해 기본 데이터 작업을 수행하는 방법을 배우게 되며, 이를 통해 리액트에서 Parse 서버 데이터베이스에서 데이터를 생성, 읽기, 업데이트 및 삭제하는 방법을 보여줍니다. 먼저 각 CRUD 작업에 대한 구성 요소 함수를 생성하고, 나중에 전체 화면 레이아웃에서 이를 사용하여 할 일 목록 앱을 완성합니다.

## 전제 조건

:::hint{type="info"}
**이 튜토리얼을 완료하려면 다음이 필요합니다:**

- React 앱이 생성되고 [Back4App에 연결됨](https://www.back4app.com/docs/react/quickstart)
- 이 가이드에서 제공하는 화면 레이아웃을 테스트/사용하려면 <font color="#2166ae">`Ant Design`</font> [라이브러리](https://ant.design/docs/react/introduce)을 설정해야 합니다.
:::

## 목표

Parse를 사용하여 React에서 기본 CRUD 애플리케이션을 구축합니다.

## 1 - 데이터 객체 생성

Parse 데이터베이스에서 데이터를 관리하는 첫 번째 단계는 데이터가 있는 것입니다. 이제 <font color="#2166ae">`createTodo` </font> 함수를 만들어 보겠습니다. 이 함수는 <font color="#2166ae">`Parse.Object`</font>의 새로운 인스턴스를 생성합니다. 할 일은 작업을 설명하는 제목 (<font color="#2166ae">`string`</font>)과 작업이 완료되었는지를 나타내는 done(<font color="#2166ae">`boolean`</font>) 필드를 가집니다.

:::CodeblockTabs
JavaScript

```javascript
1   const createTodo = async function () {
2     // This value comes from a state variable
3     const newTodoTitleValue = newTodoTitle;
4     // Creates a new Todo parse object instance
5     let Todo = new Parse.Object('Todo');
6     Todo.set('title', newTodoTitleValue);
7     Todo.set('done', false);
8     // After setting the to-do values, save it on the server
9     try {
10      await Todo.save();
11      // Success
12      alert('Success! To-do created!');
13      // Refresh to-dos list to show the new one (you will create this function later)
14      readTodos();
15      return true;
16    } catch (error) {
17      // Error can be caused by lack of Internet connection
18      alert(`Error! ${error.message}`);
19      return false;
20    };
21  };
```

```typescript
1   const createTodo = async function (): Promise<boolean> {
2     // This value comes from a state variable
3     const newTodoTitleValue: string = newTodoTitle;
4     // Creates a new Todo parse object instance
5     let Todo: Parse.Object = new Parse.Object('Todo');
6     Todo.set('title', newTodoTitleValue);
7     Todo.set('done', false);
8     // After setting the to-do values, save it on the server
9     try {
10      await Todo.save();
11      // Success
12      alert('Success! To-do created!');
13      // Refresh to-dos list to show the new one (you will create this function later)
14      readTodos();
15      return true;
16    } catch (error: any) {
17      // Error can be caused by lack of Internet connection
18      alert(`Error! ${error.message}`);
19      return false;
20    };
21  };
```
:::

데이터베이스에 <font color="#2166ae">`Todo`</font> 테이블(또는 서브클래스)이 아직 없다면, Parse는 이를 자동으로 생성하고 <font color="#2166ae">`Parse.Object`</font> 인스턴스 내에 설정된 모든 열을 추가합니다. <font color="#2166ae">`Parse.Object.set()`</font> 메서드를 사용하여 두 개의 인수를 받습니다: 필드 이름과 설정할 값입니다.

## 2 - 데이터 객체 읽기

데이터베이스에 일부 데이터를 생성한 후, 이제 애플리케이션은 서버에서 데이터를 읽고 사용자에게 보여줄 수 있습니다. 계속해서 <font color="#2166ae">`readTodos`</font> 함수를 생성하세요. 이 함수는 <font color="#2166ae">`Parse.Query`</font>를 수행하고, 결과를 상태 변수에 저장합니다.

:::CodeblockTabs
JavaScript

```javascript
1   const readTodos = async function () {
2     // Reading parse objects is done by using Parse.Query
3     const parseQuery = new Parse.Query('Todo');
4     try {
5       let todos = await parseQuery.find();
6       // Be aware that empty or invalid queries return as an empty array
7       // Set results to state variable
8       setReadResults(todos);
9       return true;
10    } catch (error) {
11      // Error can be caused by lack of Internet connection
12      alert(`Error! ${error.message}`);
13      return false;
14    };
15  };
```

```typescript
1   const readTodos = async function (): Promise<boolean> {
2     // Reading parse objects is done by using Parse.Query
3     const parseQuery: Parse.Query = new Parse.Query('Todo');
4     try {
5       let todos: Parse.Object[] = await parseQuery.find();
6       // Be aware that empty or invalid queries return as an empty array
7       // Set results to state variable
8       setReadResults(todos);
9       return true;
10    } catch (error: any) {
11      // Error can be caused by lack of Internet connection
12      alert(`Error! ${error.message}`);
13      return false;
14    };
15  };
```
:::

쿼리에 많은 제약 조건과 정렬을 적용할 수 있지만, 지금은 모든 저장된 <font color="#2166ae">`Todo`</font> 객체를 검색하는 이 간단한 쿼리에 집중하겠습니다.

## 3 - 데이터 객체 업데이트

업데이트하는 <font color="#2166ae">`Parse.Object`</font> 인스턴스는 새 인스턴스를 만드는 것과 매우 유사하지만, 이 경우에는 이전에 생성된 <font color="#2166ae">`objectId`</font>를 할당한 다음 새 값을 설정한 후 저장해야 합니다.

:::CodeblockTabs
JavaScript

```javascript
1   const updateTodo = async function (todoId, done) {
2     // Create a new Todo parse object instance and set todo id
3     let Todo = new Parse.Object('Todo');
4     Todo.set('objectId', todoId);
5     // Set new done value and save Parse Object changes
6     Todo.set('done', done);
7     try {
8       await Todo.save();
9       // Success
10      alert('Success! To-do updated!');
11      // Refresh to-dos list
12      readTodos();
13      return true;
14    } catch (error) {
15      // Error can be caused by lack of Internet connection
16      alert(`Error! ${error.message}`);
17      return false;
18    };
19  };
```

```typescript
1   const updateTodo = async function (
2     todoId: string,
3     done: boolean,
4   ): Promise<boolean> {
5     // Create a new Todo parse object instance and set todo id
6     let Todo: Parse.Object = new Parse.Object('Todo');
7     Todo.set('objectId', todoId);
8     // Set new done value and save Parse Object changes
9     Todo.set('done', done);
10    try {
11      await Todo.save();
12      // Success
13      alert('Success! To-do updated!');
14      // Refresh to-dos list
15      readTodos();
16      return true;
17    } catch (error: any) {
18      // Error can be caused by lack of Internet connection
19      alert(`Error! ${error.message}`);
20      return false;
21    };
22  };
```
:::

이 예제 앱은 할 일 목록을 나타내므로, 업데이트 함수는 추가 인수인 <font color="#2166ae">`done`</font> 값을 사용합니다. 이 값은 특정 작업이 완료되었는지를 나타냅니다.

## 4 - 데이터 객체 삭제

데이터 객체를 삭제하려면, <font color="#2166ae">`.destroy()`</font> 메서드를 호출해야 합니다. <font color="#2166ae">`Parse.Object`</font> 인스턴스에서 이를 나타냅니다. 이 작업은 되돌릴 수 없으므로 주의하세요.

:::CodeblockTabs
JavaScript

```javascript
1	const deleteTodo = async function (todoId) {
2	  // Create a new Todo parse object instance and set todo id
3	  const Todo = new Parse.Object('Todo');
4	  Todo.set('objectId', todoId);
5	  // .destroy should be called to delete a parse object
6	  try {
7	    await Todo.destroy();
8	    alert('Success! To-do deleted!');
9	    // Refresh to-dos list to remove this one
10	    readTodos();
11	    return true;
12	  } catch (error) {
13	    // Error can be caused by lack of Internet connection
14	    alert(`Error ${error.message}`);
15	    return false;
16	  };
17	};
```

```typescript
1	const deleteTodo = async function (todoId: string): Promise<boolean> {
2	  // Create a new Todo parse object instance and set todo id
3	  let Todo: Parse.Object = new Parse.Object('Todo');
4	  Todo.set('objectId', todoId);
5	  // .destroy should be called to delete a parse object
6	  try {
7	    await Todo.destroy();
8	    alert('Success! To-do deleted!');
9	    // Refresh to-dos list to remove this one
10	    readTodos();
11	    return true;
12	  } catch (error: any) {
13	    // Error can be caused by lack of Internet connection
14	    alert(`Error! ${error.message}`);
15	    return false;
16	  };
17	};
```
:::

이제 이 네 가지 함수를 완전한 컴포넌트에서 사용하여 테스트하고 모든 CRUD 작업이 제대로 작동하는지 확인해 보겠습니다.

## 5 - React 컴포넌트에서 CRUD 사용하기

여기 스타일이 적용된 사용자 인터페이스 요소( <font color="#2166ae">`Ant Design`</font> 포함), 상태 변수 및 CRUD 함수 호출을 포함한 전체 컴포넌트 코드가 있습니다. <font color="#2166ae">`TodoList.js/TodoList.tsx`</font>라는 파일에 별도의 컴포넌트를 생성해야 합니다. <font color="#2166ae">`src` </font>디렉토리에 다음 코드를 포함하거나 이를 직접 주요 애플리케이션 파일(<font color="#2166ae">`App.js/App.tsx`</font>)에 추가하세요.

:::CodeblockTabs
TodoList.js

```javascript
1   import React, { useState } from 'react';
2   import Parse from 'parse/dist/parse.min.js';
3   import './App.css';
4   import { Button, Input, List } from 'antd';
5   import {
6     CheckOutlined,
7     CloseOutlined,
8     PlusOutlined,
9     RedoOutlined,
10  } from '@ant-design/icons';
11
12  export const TodoList = () => {
13    // State variables
14    const [readResults, setReadResults] = useState([]);
15    const [newTodoTitle, setNewTodoTitle] = useState('');
16
17    // Functions used by the screen components
18    const createTodo = async function () {
19      // This value comes from a state variable
20      const newTodoTitleValue = newTodoTitle;
21      // Creates a new Todo parse object instance
22      let Todo = new Parse.Object('Todo');
23      Todo.set('title', newTodoTitleValue);
24      Todo.set('done', false);
25      // After setting the to-do values, save it on the server
26      try {
27        await Todo.save();
28        // Success
29        alert('Success! To-do created!');
30        // Refresh to-dos list to show the new one (you will create this function later)
31        readTodos();
32        return true;
33      } catch (error) {
34        // Error can be caused by lack of Internet connection
35        alert(`Error! ${error.message}`);
36        return false;
37      }
38    };
39
40    const readTodos = async function () {
41      // Reading parse objects is done by using Parse.Query
42      const parseQuery = new Parse.Query('Todo');
43      try {
44        let todos = await parseQuery.find();
45        // Be aware that empty or invalid queries return as an empty array
46        // Set results to state variable
47        setReadResults(todos);
48        return true;
49      } catch (error) {
50        // Error can be caused by lack of Internet connection
51        alert(`Error! ${error.message}`);
52        return false;
53      }
54    };
55
56    const updateTodo = async function (todoId, done) {
57      // Create a new to-do parse object instance and set todo id
58      let Todo = new Parse.Object('Todo');
59      Todo.set('objectId', todoId);
60      // Set new done value and save Parse Object changes
61      Todo.set('done', done);
62      try {
63        await Todo.save();
64        // Success
65        alert('Success! To-do updated!');
66        // Refresh todos list
67        readTodos();
68        return true;
69      } catch (error) {
70        // Error can be caused by lack of Internet connection
71        alert(`Error! ${error.message}`);
72        return false;
73      }
74    };
75
76    const deleteTodo = async function (todoId) {
77      // Create a new Todo parse object instance and set todo id
78      let Todo = new Parse.Object('Todo');
79      Todo.set('objectId', todoId);
80      // .destroy should be called to delete a parse object
81      try {
82        await Todo.destroy();
83        alert('Success! To-do deleted!');
84        // Refresh to-dos list to remove this one
85        readTodos();
86        return true;
87      } catch (error) {
88        // Error can be caused by lack of Internet connection
89        alert(`Error! ${error.message}`);
90        return false;
91      }
92    };
93
94    return (
95      <div>
96        <div className="header">
97          <img
98            className="header_logo"
99            alt="Back4App Logo"
100           src={
101             'https://blog.back4app.com/wp-content/uploads/2019/05/back4app-white-logo-500px.png'
102           }
103         />
104         <p className="header_text_bold">{'React on Back4App'}</p>
105         <p className="header_text">{'To-do List'}</p>
106       </div>
107       <div className="container">
108         <div className="flex_between">
109           <h2 className="list_heading">Todo List</h2>
110           {/* To-do read (refresh) button */}
111           <Button
112             type="primary"
113             shape="circle"
114             color={'#208AEC'}
115             size={'default'}
116             onClick={readTodos}
117             icon={<RedoOutlined />}
118           ></Button>
119         </div>
120         <div className="new_todo_wrapper flex_between">
121           {/* Todo create text input */}
122           <Input
123             value={newTodoTitle}
124             onChange={(event) => setNewTodoTitle(event.target.value)}
125             placeholder="New Todo"
126             size="large"
127           />
128           {/* Todo create button */}
129           <Button
130             type="primary"
131             className="create_todo_button"
132             color={'#208AEC'}
133             size={'large'}
134             onClick={createTodo}
135             icon={<PlusOutlined />}
136           >
137             Add
138           </Button>
139         </div>
140         <div>
141           {/* Todo read results list */}
142           {readResults !== null &&
143             readResults !== undefined &&
144             readResults.length > 0 && (
145               <List
146                 dataSource={readResults}
147                 renderItem={(item) => (
148                   <List.Item className="todo_item">
149                     <p
150                       className={
151                         item.get('done') === true
152                           ? 'todo_text_done'
153                           : 'todo_text'
154                       }
155                     >
156                       {item.get('title')}
157                     </p>
158                     <div className="flex_row">
159                       {/* Todo update button */}
160                       {item.get('done') !== true && (
161                         <Button
162                           type="primary"
163                           shape="circle"
164                           className="todo_button"
165                           onClick={() => updateTodo(item.id, true)}
166                           icon={
167                             <CheckOutlined className="todo_button_icon_done" />
168                           }
169                         ></Button>
170                       )}
171                       {/* Todo delete button */}
172                       <Button
173                         type="primary"
174                         shape="circle"
175                         className="todo_button"
176                         onClick={() => deleteTodo(item.id)}
177                         icon={
178                           <CloseOutlined className="todo_button_icon_remove" />
179                         }
180                       ></Button>
181                     </div>
182                   </List.Item>
183                 )}
184               />
185             )}
186         </div>
187       </div>
188     </div>
189   );
190 };
```

TodoList.tsx

```typescript
1   import React, { useState, FC, ReactElement } from 'react';
2   import './App.css';
3   import { Button, Input, List } from 'antd';
4   import {
5     CheckOutlined,
6     CloseOutlined,
7     PlusOutlined,
8     RedoOutlined,
9   } from '@ant-design/icons';
10  const Parse = require('parse/dist/parse.min.js');
11
12  export const TodoList: FC<{}> = (): ReactElement => {
13    // State variables
14    const initialReadResults: Parse.Object[] = [];
15    const [readResults, setReadResults] = useState(initialReadResults);
16    const [newTodoTitle, setNewTodoTitle] = useState('');
17
18    // Functions used by the screen components
19    const createTodo = async function (): Promise<boolean> {
20      // This value comes from a state variable
21      const newTodoTitleValue: string = newTodoTitle;
22      // Creates a new Todo parse object instance
23      let Todo: Parse.Object = new Parse.Object('Todo');
24      Todo.set('title', newTodoTitleValue);
25      Todo.set('done', false);
26      // After setting the to-do values, save it on the server
27      try {
28        await Todo.save();
29        // Success
30        alert('Success! To-do created!');
31        // Refresh to-dos list to show the new one (you will create this function later)
32        readTodos();
33        return true;
34      } catch (error: any) {
35        // Error can be caused by lack of Internet connection
36        alert('Error!' + error.message);
37        return false;
38      }
39    };
40
41    const readTodos = async function (): Promise<boolean> {
42      // Reading parse objects is done by using Parse.Query
43      const parseQuery: Parse.Query = new Parse.Query('Todo');
44      try {
45        let todos: Parse.Object[] = await parseQuery.find();
46        // Be aware that empty or invalid queries return as an empty array
47        // Set results to state variable
48        setReadResults(todos);
49        return true;
50      } catch (error: any) {
51        // Error can be caused by lack of Internet connection
52        alert('Error!' + error.message);
53        return false;
54      }
55    };
56
57    const updateTodo = async function (todoId: string, done: boolean): Promise<boolean> {
58      // Create a new to-do parse object instance and set todo id
59      let Todo: Parse.Object = new Parse.Object('Todo');
60      Todo.set('objectId', todoId);
61      // Set new done value and save Parse Object changes
62      Todo.set('done', done);
63      try {
64        await Todo.save();
65        // Success
66        alert('Success! To-do updated!');
67        // Refresh todos list
68        readTodos();
69        return true;
70      } catch (error: any) {
71        // Error can be caused by lack of Internet connection
72        alert('Error!' + error.message);
73        return false;
74      }
75    };
76
77    const deleteTodo = async function (todoId: string): Promise<boolean> {
78      // Create a new Todo parse object instance and set todo id
79      let Todo: Parse.Object = new Parse.Object('Todo');
80      Todo.set('objectId', todoId);
81      // .destroy should be called to delete a parse object
82      try {
83        await Todo.destroy();
84        alert('Success! To-do deleted!');
85        // Refresh to-dos list to remove this one
86        readTodos();
87        return true;
88      } catch (error: any) {
89        // Error can be caused by lack of Internet connection
90        alert('Error!' + error.message);
91        return false;
92      }
93    };
94
95    return (
96      <div>
97        <div className="header">
98          <img
99            className="header_logo"
100           alt="Back4App Logo"
101           src={
102             'https://blog.back4app.com/wp-content/uploads/2019/05/back4app-white-logo-500px.png'
103           }
104         />
105         <p className="header_text_bold">{'React on Back4App'}</p>
106         <p className="header_text">{'To-do List'}</p>
107       </div>
108       <div className="container">
109         <div className="flex_between">
110           <h2 className="list_heading">Todo List</h2>
111           {/* To-do read (refresh) button */}
112           <Button
113             type="primary"
114             shape="circle"
115             color={'#208AEC'}
116             onClick={readTodos}
117             icon={<RedoOutlined />}
118           ></Button>
119         </div>
120         <div className="new_todo_wrapper flex_between">
121           {/* Todo create text input */}
122           <Input
123             value={newTodoTitle}
124             onChange={(event: {target: {value: string}}) => setNewTodoTitle(event.target.value)}
125             placeholder="New Todo"
126             size="large"
127           />
128           {/* Todo create button */}
129           <Button
130             type="primary"
131             className="create_todo_button"
132             color={'#208AEC'}
133             size={'large'}
134             onClick={createTodo}
135             icon={<PlusOutlined />}
136           >
137             Add
138           </Button>
139         </div>
140         <div>
141           {/* Todo read results list */}
142           {readResults !== null &&
143             readResults !== undefined &&
144             readResults.length > 0 && (
145               <List
146                 dataSource={readResults}
147                 renderItem={(item: Parse.Object) => (
148                   <List.Item className="todo_item">
149                     <p
150                       className={
151                         item.get('done') === true
152                           ? 'todo_text_done'
153                           : 'todo_text'
154                       }
155                     >
156                       {item.get('title')}
157                     </p>
158                     <div className="flex_row">
159                       {/* Todo update button */}
160                       {item.get('done') !== true && (
161                         <Button
162                           type="primary"
163                           shape="circle"
164                           className="todo_button"
165                           onClick={() => updateTodo(item.id, true)}
166                           icon={
167                             <CheckOutlined className="todo_button_icon_done" />
168                           }
169                         ></Button>
170                       )}
171                       {/* Todo delete button */}
172                       <Button
173                         type="primary"
174                         shape="circle"
175                         className="todo_button"
176                         onClick={() => deleteTodo(item.id)}
177                         icon={
178                           <CloseOutlined className="todo_button_icon_remove" />
179                         }
180                       ></Button>
181                     </div>
182                   </List.Item>
183                 )}
184               />
185             )}
186         </div>
187       </div>
188     </div>
189   );
190 };
```
:::

또한, 다음 CSS 스타일을 <font color="#2166ae">`App.css`</font> 파일의 끝에 추가하세요:

```css
1   /* ... */
2   /* Your other styles */
3
4   /* Back4App Guide Styles */
5
6   html {
7	   box-sizing: border-box;
8	   outline: none;
9	   overflow: auto;
10  }
11
12  *,
13  *:before,
14  *:after {
15	  margin: 0;
16	  padding: 0;
17	  box-sizing: inherit;
18  }
19
20  h1,
21  h2,
22  h3,
23  h4,
24  h5,
25  h6 {
26    margin: 0;
27  }
28
29  p {
30    margin: 0;
31  }
32
33  body {
34	  margin: 0;
35	  background-color: #fff;
36  }
37
38  .container {
39    width: 100%;
40    max-width: 600px;
41    margin: auto;
42    padding: 20px 0;
43  }
44
45  .wrapper {
46    width: '90%';
47    align-self: 'center';
48  }
49
50  .header {
51    align-items: center;
52    padding: 25px 0;
53    background-color: #208AEC;
54  }
55
56  .header_logo {
57    height: 55px;
58    margin-bottom: 20px;
59    object-fit: contain;
60  }
61
62  .header_text_bold {
63    margin-bottom: 3px;
64    color: rgba(255, 255, 255, 0.9);
65    font-size: 16px;
66    font-weight: bold;
67  }
68
69  .header_text {
70    color: rgba(255, 255, 255, 0.9);
71    font-size: 15px;
72  }
73
74  .flex_row {
75    display: flex;
76  }
77
78  .flex_between {
79    display: flex;
80    align-items: center;
81    justify-content: space-between;
82  }
83
84  .list_heading {
85    font-weight: bold;
86  }
87
88  .new_todo_wrapper {
89    margin-top: 20px;
90    margin-bottom: 10px;
91  }
92
93  .new_todo_wrapper > input {
94    margin-right: 20px;
95  }
96
97  .todo_item {
98    border-bottom-width: 1;
99    border-bottom-color: 'rgba(0, 0, 0, 0.12)';
100  }
101
102  .todo_text {
103    font-size: 15px;
104  }
105
106  .todo_text_done {
107    color: rgba(0, 0, 0, 0.3);
108    font-size: 15px;
109    text-decoration-line: line-through;
110  }
111
112  .todo_button {
113    width: 32px;
114    height: 32px;
115    margin-left: 5px;
116    background-color: transparent;
117    border-radius: 50px;
118    border: none;
119    cursor: pointer;
120  }
121
122  .todo_button:hover,
123  .todo_button:focus {
124    background-color: rgba(0, 0, 0, 0.1);
125  }
126
127  .todo_button_icon_done {
128    color: #52c41a;
129    font-size: 16px;
130  }
131
132  .todo_button_icon_remove {
133    color: #f5222d;
134    font-size: 16px;
135  }
```

구성 요소가 제대로 설정되었다면, 앱을 실행한 후 다음과 같은 화면을 보게 될 것입니다:

![](https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/D0I4xfjjvDNq4inZAbUcd_image.png)

입력 상자에 제목을 하나씩 입력하고 <font color="#2166ae">`추가` </font>버튼을 눌러 할 일을 추가하세요. 모든 작업이 성공적으로 생성된 후, <font color="#2166ae">`createTodo` </font>함수가 <font color="#2166ae">`readTodos` </font>함수를 트리거하여 작업 목록을 자동으로 새로 고칩니다. 이제 다음과 같은 상당한 할 일 목록이 있어야 합니다:

![](https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/vEEcPYfh_NX3Y6eEhsNzP_image.png)

이제 체크마크를 클릭하여 작업을 완료로 표시할 수 있으며, 이로 인해 해당 작업의 <font color="#2166ae">`완료` </font>값이 true로 업데이트되고 왼쪽의 아이콘 상태가 변경됩니다.

![](https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/mrjtEdu2yMPdDh7Xh8c8t_image.png)

이제 남은 데이터 작업은 삭제 작업입니다. 이는 할 일 목록 객체의 가장 오른쪽에 있는 쓰레기통 아이콘을 눌러 수행할 수 있습니다. 객체를 성공적으로 삭제한 후에는 다음과 같은 경고 메시지를 받게 됩니다:

![](https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/qs_4jFok4k9SHdbIkNehG_image.png)

## 결론

이 가이드를 마치면서, React에서 Parse를 사용하여 기본 데이터 작업(CRUD)을 수행하는 방법을 배웠습니다. 다음 가이드에서는 Parse에서 지원하는 데이터 유형과 이를 사용하는 방법을 보여드리겠습니다.
