---
title: React와 Parse로 데이터 쿼리 수행하기 - 개발자 가이드
slug: docs-kr/react/data-objects/react-query
description: React와 Back4App을 통해 Parse에서 데이터 쿼리 수행 및 React 컴포넌트 구현 방법을 배워보세요.
image: https://www.back4app.com/images/logo-social.png
createdAt: 2024-03-18T20:09:48.112Z
---

# React에서 Parse를 사용한 쿼리

## 소개

이 가이드에서는 Parse에서 기본 쿼리를 수행하고 이러한 쿼리를 사용하여 React 컴포넌트를 구현합니다. Back4App과 React를 사용하여 현실적인 데이터를 설정하고 쿼리하는 방법을 배웁니다.

## 전제 조건

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

- React 앱이 생성되고 [Back4App에 연결됨](https://www.back4app.com/docs/react/quickstart).
-  이 가이드의 예제 프로젝트를 실행하려면 [<font color="#2166ae">`Ant Design`</font> 라이브러리를 설정해야 합니다.](https://ant.design/)
:::

## 목표

React 애플리케이션에서 Back4App에 저장된 데이터를 쿼리합니다.

## 1 - Parse.Query 클래스 이해하기

모든 Parse 쿼리 작업은 <font color="#2166ae">`Parse.Query`</font> 객체 유형을 사용하며, 이는 앱 전반에 걸쳐 데이터베이스에서 특정 데이터를 검색하는 데 도움이 됩니다. <font color="#2166ae">`Parse.Query`</font>는 retrieve 메서드(예: <font color="#2166ae">`Parse.Query.find` </font> 또는 <font color="#2166ae">`Parse.Query.get`</font> 호출 후에만 해결되므로, 쿼리를 설정하고 실제로 호출되기 전에 여러 수정자를 연결할 수 있습니다.

새로운 <font color="#2166ae">`Parse.Query`</font>, 원하는 <font color="#2166ae">`Parse.Object`</font> 서브클래스를 매개변수로 전달해야 합니다. 이 서브클래스는 쿼리 결과를 포함하게 됩니다. 아래에서 볼 수 있는 예제 쿼리에서는 가상의 <font color="#2166ae">`Profile` </font> 서브클래스가 쿼리되고 있습니다.

```javascript
1   // This will create your query
2   let parseQuery = new Parse.Query("Profile");
3   // The query will resolve only after calling this method
4   let queryResult = await parseQuery.find();
```

다음에 대한 자세한 내용을 읽을 수 있습니다 <font color="#2166ae">`Parse.Query`</font> 클래스 [공식 문서에서 여기](https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Query.html).&#x20;

## 2 - Back4App에 데이터 저장하기

이 가이드에서 쿼리의 대상이 될 <font color="#2166ae">`Profile` </font> 클래스를 생성해 보겠습니다. Parse JS 콘솔에서는 JavaScript 코드를 직접 실행하여 JS SDK 명령을 사용하여 애플리케이션 데이터베이스 내용을 쿼리하고 업데이트할 수 있습니다. 아래 코드를 JS 콘솔에서 실행하고 Back4App에 데이터를 삽입하세요.

대시보드에서 JS 콘솔이 어떻게 보이는지 확인해 보세요:

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

사용자 <font color="#2166ae">`프로필`</font> 클래스를 다음 예제 내용으로 생성하세요:

```javascript
1   // Add Profile objects and create table
2   // Adam Sandler
3   let Profile = new Parse.Object('Profile');
4   Profile.set('name', 'Adam Sandler');
5   Profile.set('birthDay', new Date('09/09/1966'));
6   Profile.set('friendCount', 2);
7   Profile.set('favoriteFoods', ['Lobster', 'Bread']);
8   await Profile.save();
9
10  // Adam Levine
11  Profile = new Parse.Object('Profile');
12  Profile.set('name', 'Adam Levine');
13  Profile.set('birthDay', new Date('03/18/1979'));
14  Profile.set('friendCount', 52);
15  Profile.set('favoriteFoods', ['Cake', 'Bread']);
16  await Profile.save();
17
18  // Carson Kressley
19  Profile = new Parse.Object('Profile');
20  Profile.set('name', 'Carson Kressley');
21  Profile.set('birthDay', new Date('11/11/1969'));
22  Profile.set('friendCount', 12);
23  Profile.set('favoriteFoods', ['Fish', 'Cookies']);
24  await Profile.save();
25
26  // Dan Aykroyd
27  Profile = new Parse.Object('Profile');
28  Profile.set('name', 'Dan Aykroyd');
29  Profile.set('birthDay', new Date('07/01/1952'));
30  Profile.set('friendCount', 66);
31  Profile.set('favoriteFoods', ['Jam', 'Peanut Butter']);
32  await Profile.save();
33
34  // Eddie Murphy
35  Profile = new Parse.Object('Profile');
36  Profile.set('name', 'Eddie Murphy');
37  Profile.set('birthDay', new Date('04/03/1961'));
38  Profile.set('friendCount', 49);
39  Profile.set('favoriteFoods', ['Lettuce', 'Pepper']);
40  await Profile.save();
41
42  // Fergie
43  Profile = new Parse.Object('Profile');
44  Profile.set('name', 'Fergie');
45  Profile.set('birthDay', new Date('03/27/1975'));
46  Profile.set('friendCount', 55);
47  Profile.set('favoriteFoods', ['Lobster', 'Shrimp']);
48  await Profile.save();
49
50  console.log('Success!');
```

## 3 - 데이터 쿼리하기

이제 클래스가 채워졌으므로, 기본 쿼리를 수행할 수 있습니다. 이름으로 결과를 필터링하는 것부터 시작해 보겠습니다. 이는 문자열 유형 필드로, <font color="#2166ae">`프로필` </font>이름이 포함된 값을 검색합니다. <font color="#2166ae">`아담` </font>을(를) 사용하여 <font color="#2166ae">`Parse.Query.contains`</font> 메서드를 사용합니다:

```javascript
1   // Create your query
2   let parseQuery = new Parse.Query('Profile');
3
4   // `contains` is a basic query method that checks if string field
5   // contains a specific substring
6   parseQuery.contains('name', 'Adam');
7
8   // The query will resolve only after calling this method, retrieving
9   // an array of `Parse.Objects`
10  let queryResults = await parseQuery.find();
11
12  // Let's show the results
13  for (let result of queryResults) {
14    // You access `Parse.Objects` attributes by using `.get`
15    console.log(result.get('name'));
16  };
```

이제 숫자 유형 필드로 쿼리해 보겠습니다. <font color="#2166ae">`friendCount` </font>를 사용하여 또 다른 일반 쿼리 메서드인 <font color="#2166ae">`Parse.Query.greaterThan`</font>. 이 경우, 친구 수가 20보다 많은 <font color="#2166ae">`프로필` </font>을(를) 원합니다.

```javascript
1   // Create your query
2   let parseQuery = new Parse.Query('Profile');
3
4   // `greaterThan` is a basic query method that does what it
5   // says on the tin
6   parseQuery.greaterThan('friendCount', 20);
7
8   // The query will resolve only after calling this method, retrieving
9   // an array of `Parse.Objects`
10  let queryResults = await parseQuery.find();
11
12  // Let's show the results
13  for (let result of queryResults) {
14    // You access `Parse.Objects` attributes by using `.get`
15    console.log(`name: ${result.get('name')}, friend count: ${result.get('friendCount')}`);
16  };
```

다른 반복 쿼리 메서드는 <font color="#2166ae">`Parse.Query.ascending`</font> 및 <font color="#2166ae">`Parse.Query.descending`</font>, 쿼리를 정렬하는 역할을 합니다. 이 정렬은 대부분의 데이터 유형에서 수행할 수 있으므로, 날짜 필드 <font color="#2166ae">`birthDay` </font>를 기준으로 가장 어린 사람으로 쿼리를 정렬해 보겠습니다.

```javascript
1   // Create your query
2   let parseQuery = new Parse.Query('Profile');
3
4   // `descending` and `ascending` can and should be chained
5   // with other query methods to improve your queries
6   parseQuery.descending('birthDay');
7
8   // The query will resolve only after calling this method, retrieving
9   // an array of `Parse.Objects`
10  let queryResults = await parseQuery.find();
11
12  // Let's show the results
13  for (let result of queryResults) {
14    // You access `Parse.Objects` attributes by using `.get`
15    console.log(`name: ${result.get('name')}, birthday: ${result.get('birthDay')}`);
16  };
```

앞서 언급했듯이, 더 정교한 결과를 얻기 위해 쿼리 메서드를 연결할 수 있으며 연결해야 합니다. 그러면 이전 예제를 단일 쿼리 요청으로 결합해 보겠습니다:

```javascript
1   // Create your query
2   let parseQuery = new Parse.Query('Profile');
3
4   parseQuery.contains('name', 'Adam');
5   parseQuery.greaterThan('friendCount', 20);
6   parseQuery.descending('birthDay');
7
8   // The query will resolve only after calling this method, retrieving
9   // an array of `Parse.Objects`
10  let queryResults = await parseQuery.find();
11
12  // Let's show the results
13  for (let result of queryResults) {
14    // You access `Parse.Objects` attributes by using `.get`
15    console.log(`name: ${result.get('name')}, friend count: ${result.get('friendCount')}, birthday: ${result.get('birthDay')}`);
16  };
```

## 4 - React 컴포넌트에서 쿼리하기

이제 React의 컴포넌트 내에서 예제 쿼리를 사용해 보겠습니다. 결과를 보여주는 목록과 쿼리를 호출하기 위한 4개의 버튼이 있는 간단한 인터페이스를 가지고 있습니다. 컴포넌트 코드의 배치는 다음과 같으며, <font color="#2166ae">`doQuery` </font> 함수가 포함되어 있으며, 이전의 예제 코드 형식을 포함하고 있습니다.

:::CodeblockTabs
JavaScript

```javascript
1	import React, { useState } from 'react';
2	import Parse from 'parse/dist/parse.min.js';
3	import './App.css';
4	import { Button, Divider } from 'antd';
5	import { CloseOutlined, SearchOutlined } from '@ant-design/icons';
6	
7	export const QueryBasic = () => {
8	  // State variable
9	  const [queryResults, setQueryResults] = useState();
10	
11	  const doQueryByName = async function () {
12	    // Create our Parse.Query instance so methods can be chained
13	    // Reading parse objects is done by using Parse.Query
14	    const parseQuery = new Parse.Query('Profile');
15	
16	    // `contains` is a basic query method that checks if string field
17	    // contains a specific substring
18	    parseQuery.contains('name', 'Adam');
19	
20	    try {
21	      let profiles = await parseQuery.find();
22	      setQueryResults(profiles);
23	      return true;
24	    } catch (error) {
25	      // Error can be caused by lack of Internet connection
26	      alert(`Error! ${error.message}`);
27	      return false;
28	    }
29	  };
30	
31	  const doQueryByFriendCount = async function () {
32	    // Create our Parse.Query instance so methods can be chained
33	    // Reading parse objects is done by using Parse.Query
34	    const parseQuery = new Parse.Query('Profile');
35	
36	    // `greaterThan` is a basic query method that does what it
37	    // says on the tin
38	    parseQuery.greaterThan('friendCount', 20);
39	
40	    try {
41	      let profiles = await parseQuery.find();
42	      setQueryResults(profiles);
43	      return true;
44	    } catch (error) {
45	      // Error can be caused by lack of Internet connection
46	      alert(`Error! ${error.message}`);
47	      return false;
48	    }
49	  };
50	
51	  const doQueryByOrdering = async function () {
52	    // Create our Parse.Query instance so methods can be chained
53	    // Reading parse objects is done by using Parse.Query
54	    const parseQuery = new Parse.Query('Profile');
55	
56	    // `descending` and `ascending` can and should be chained
57	    // with other query methods to improve your queries
58	    parseQuery.descending('birthDay');
59	
60	    try {
61	      let profiles = await parseQuery.find();
62	      setQueryResults(profiles);
63	      return true;
64	    } catch (error) {
65	      // Error can be caused by lack of Internet connection
66	      alert(`Error! ${error.message}`);
67	      return false;
68	    }
69	  };
70	
71	  const doQueryByAll = async function () {
72	    // Create our Parse.Query instance so methods can be chained
73	    // Reading parse objects is done by using Parse.Query
74	    const parseQuery = new Parse.Query('Profile');
75	
76	    parseQuery.contains('name', 'Adam');
77	    parseQuery.greaterThan('friendCount', 20);
78	    parseQuery.descending('birthDay');
79	
80	    try {
81	      let profiles = await parseQuery.find();
82	      setQueryResults(profiles);
83	      return true;
84	    } catch (error) {
85	      // Error can be caused by lack of Internet connection
86	      alert(`Error! ${error.message}`);
87	      return false;
88	    }
89	  };
90	
91	  const clearQueryResults = async function () {
92	    setQueryResults(undefined);
93	    return true;
94	  };
95	
96	  return (
97	    <div>
98	      <div className="header">
99	        <img
100	          className="header_logo"
101	          alt="Back4App Logo"
102	          src={
103	            'https://blog.back4app.com/wp-content/uploads/2019/05/back4app-white-logo-500px.png'
104	          }
105	        />
106	        <p className="header_text_bold">{'React on Back4App'}</p>
107	        <p className="header_text">{'Basic Queries'}</p>
108	      </div>
109	      <div className="container">
110	        <div className="flex_between">
111	          <h2 className="heading">{'Query List'}</h2>
112	          <div className="flex">
113	            <Button
114	              onClick={() => doQueryByName()}
115	              type="primary"
116	              className="heading_button"
117	              color={'#208AEC'}
118	              icon={<SearchOutlined />}
119	            >
120	              BY NAME
121	            </Button>
122	            <Button
123	              onClick={() => doQueryByFriendCount()}
124	              type="primary"
125	              className="heading_button"
126	              color={'#208AEC'}
127	              icon={<SearchOutlined />}
128	            >
129	              BY FRIEND COUNT
130	            </Button>
131	            <Button
132	              onClick={() => doQueryByOrdering()}
133	              type="primary"
134	              className="heading_button"
135	              color={'#208AEC'}
136	              icon={<SearchOutlined />}
137	            >
138	              BY ORDERING
139	            </Button>
140	            <Button
141	              onClick={() => doQueryByAll()}
142	              type="primary"
143	              className="heading_button"
144	              color={'#208AEC'}
145	              icon={<SearchOutlined />}
146	            >
147	              BY ALL
148	            </Button>
149	            <Button
150	              onClick={() => clearQueryResults()}
151	              type="primary"
152	              className="heading_button"
153	              color={'#208AEC'}
154	              icon={<CloseOutlined />}
155	            >
156	              CLEAR
157	            </Button>
158	          </div>
159	        </div>
160	        <Divider />
161	        <div className="flex_between">
162	          <div className="flex_child">
163	            {/* Query list */}
164	            {queryResults !== undefined &&
165	              queryResults.map((profile, index) => (
166	                <div className="list_item" key={`${index}`}>
167	                  <p className="list_item_title">{`${profile.get('name')}`}</p>
168	                  <p className="list_item_description">{`Friend count: ${profile.get(
169	                    'friendCount'
170	                  )}, Birthday: ${profile.get('birthDay')}`}</p>
171	                </div>
172	              ))}
173	            {queryResults !== undefined && queryResults.length <= 0 ? (
174	              <p>{'No results here!'}</p>
175	            ) : null}
176	          </div>
177	        </div>
178	      </div>
179	    </div>
180	  );
181	};
```

TypeScript

```typescript
1	import React, { useState, FC, ReactElement } from 'react';
2	import './App.css';
3	import { Button, Divider } from 'antd';
4	import { CloseOutlined, SearchOutlined } from '@ant-design/icons';
5	const Parse = require('parse/dist/parse.min.js');
6	
7	export const QueryBasic: FC<{}> = (): ReactElement => {
8	  // State variable
9	  const [queryResults, setQueryResults] = useState<Parse.Object[]>();
10	
11	  const doQueryByName = async function (): Promise<boolean> {
12	    // Create our Parse.Query instance so methods can be chained
13	    // Reading parse objects is done by using Parse.Query
14	    const parseQuery: Parse.Query = new Parse.Query('Profile');
15	
16	    // `contains` is a basic query method that checks if string field
17	    // contains a specific substring
18	    parseQuery.contains('name', 'Adam');
19	
20	    try {
21	      let profiles: Parse.Object[] = await parseQuery.find();
22	      setQueryResults(profiles);
23	      return true;
24	    } catch (error: any) {
25	      // Error can be caused by lack of Internet connection
26	      alert(`Error! ${error.message}`);
27	      return false;
28	    }
29	  };
30	
31	  const doQueryByFriendCount = async function (): Promise<boolean> {
32	    // Create our Parse.Query instance so methods can be chained
33	    // Reading parse objects is done by using Parse.Query
34	    const parseQuery: Parse.Query = new Parse.Query('Profile');
35	
36	    // `greaterThan` is a basic query method that does what it
37	    // says on the tin
38	    parseQuery.greaterThan('friendCount', 20);
39	
40	    try {
41	      let profiles: Parse.Object[] = await parseQuery.find();
42	      setQueryResults(profiles);
43	      return true;
44	    } catch (error: any) {
45	      // Error can be caused by lack of Internet connection
46	      alert(`Error! ${error.message}`);
47	      return false;
48	    }
49	  };
50	
51	  const doQueryByOrdering = async function (): Promise<boolean> {
52	    // Create our Parse.Query instance so methods can be chained
53	    // Reading parse objects is done by using Parse.Query
54	    const parseQuery: Parse.Query = new Parse.Query('Profile');
55	
56	    // `descending` and `ascending` can and should be chained
57	    // with other query methods to improve your queries
58	    parseQuery.descending('birthDay');
59	
60	    try {
61	      let profiles: Parse.Object[] = await parseQuery.find();
62	      setQueryResults(profiles);
63	      return true;
64	    } catch (error: any) {
65	      // Error can be caused by lack of Internet connection
66	      alert(`Error! ${error.message}`);
67	      return false;
68	    }
69	  };
70	
71	  const doQueryByAll = async function (): Promise<boolean> {
72	    // Create our Parse.Query instance so methods can be chained
73	    // Reading parse objects is done by using Parse.Query
74	    const parseQuery: Parse.Query = new Parse.Query('Profile');
75	
76	    parseQuery.contains('name', 'Adam');
77	    parseQuery.greaterThan('friendCount', 20);
78	    parseQuery.descending('birthDay');
79	
80	    try {
81	      let profiles: Parse.Object[] = await parseQuery.find();
82	      setQueryResults(profiles);
83	      return true;
84	    } catch (error: any) {
85	      // Error can be caused by lack of Internet connection
86	      alert(`Error! ${error.message}`);
87	      return false;
88	    }
89	  };
90	
91	  const clearQueryResults = async function (): Promise<boolean> {
92	    setQueryResults(undefined);
93	    return true;
94	  };
95	
96	  return (
97	    <div>
98	      <div className="header">
99	        <img
100	          className="header_logo"
101	          alt="Back4App Logo"
102	          src={
103	            'https://blog.back4app.com/wp-content/uploads/2019/05/back4app-white-logo-500px.png'
104	          }
105	        />
106	        <p className="header_text_bold">{'React on Back4App'}</p>
107	        <p className="header_text">{'Basic Queries'}</p>
108	      </div>
109	      <div className="container">
110	        <div className="flex_between">
111	          <h2 className="heading">{'Query List'}</h2>
112	          <div className="flex">
113	            <Button
114	              onClick={() => doQueryByName()}
115	              type="primary"
116	              className="heading_button"
117	              color={'#208AEC'}
118	              icon={<SearchOutlined />}
119	            >
120	              BY NAME
121	            </Button>
122	            <Button
123	              onClick={() => doQueryByFriendCount()}
124	              type="primary"
125	              className="heading_button"
126	              color={'#208AEC'}
127	              icon={<SearchOutlined />}
128	            >
129	              BY FRIEND COUNT
130	            </Button>
131	            <Button
132	              onClick={() => doQueryByOrdering()}
133	              type="primary"
134	              className="heading_button"
135	              color={'#208AEC'}
136	              icon={<SearchOutlined />}
137	            >
138	              BY ORDERING
139	            </Button>
140	            <Button
141	              onClick={() => doQueryByAll()}
142	              type="primary"
143	              className="heading_button"
144	              color={'#208AEC'}
145	              icon={<SearchOutlined />}
146	            >
147	              BY ALL
148	            </Button>
149	            <Button
150	              onClick={() => clearQueryResults()}
151	              type="primary"
152	              className="heading_button"
153	              color={'#208AEC'}
154	              icon={<CloseOutlined />}
155	            >
156	              CLEAR
157	            </Button>
158	          </div>
159	        </div>
160	        <Divider />
161	        <div className="flex_between">
162	          <div className="flex_child">
163	            {/* Query list */}
164	            {queryResults !== undefined &&
165	              queryResults.map((profile: Parse.Object, index: number) => (
166	                <div className="list_item" key={`${index}`}>
167	                  <p className="list_item_title">{`${profile.get('name')}`}</p>
168	                  <p className="list_item_description">{`Friend count: ${profile.get(
169	                    'friendCount'
170	                  )}, Birthday: ${profile.get('birthDay')}`}</p>
171	                </div>
172	              ))}
173	            {queryResults !== undefined &&
174	            queryResults.length <= 0 ? (
175	              <p>{'No results here!'}</p>
176	            ) : null}
177	          </div>
178	        </div>
179	      </div>
180	    </div>
181	  );
182	};
```
:::

다음 클래스를 <font color="#2166ae">`App.css`</font> 파일에 추가하여 모든 인터페이스 요소를 올바르게 렌더링하세요:

```css
1   html {
2     box-sizing: border-box;
3     outline: none;
4     overflow: auto;
5   }
6
7   *,
8   *:before,
9   *:after {
10    margin: 0;
11    padding: 0;
12    box-sizing: inherit;
13  }
14
15  h1,
16  h2,
17  h3,
18  h4,
19  h5,
20  h6 {
21    margin: 0;
22    font-weight: bold;
23  }
24
25  p {
26   margin: 0;
27  }
28
29  body {
30    margin: 0;
31    background-color: #fff;
32  }
33
34  .container {
35    width: 100%;
36    max-width: 900px;
37    margin: auto;
38    padding: 20px 0;
39    text-align: left;
40  }
41
42  .header {
43    align-items: center;
44    padding: 25px 0;
45    background-color: #208AEC;
46  }
47
48  .header_logo {
49    height: 55px;
50    margin-bottom: 20px;
51    object-fit: contain;
52  }
53
54  .header_text_bold {
55    margin-bottom: 3px;
56    color: rgba(255, 255, 255, 0.9);
57    font-size: 16px;
58    font-weight: bold;
59  }
60
61  .header_text {
62    color: rgba(255, 255, 255, 0.9);
63    font-size: 15px;
64  }
65
66  .heading {
67    font-size: 22px;
68  }
69
70  .flex {
71    display: flex;
72  }
73
74  .flex_between {
75    display: flex;
76    justify-content: space-between;
77  }
78
79  .flex_child {
80    flex: 0 0 45%;
81  }
82
83  .heading_button {
84    margin-left: 12px;
85  }
86
87  .list_item {
88    padding-bottom: 15px;
89    margin-bottom: 15px;
90    border-bottom: 1px solid rgba(0,0,0,0.06);
91    text-align: left;
92  }
93
94  .list_item_title {
95    color: rgba(0,0,0,0.87);
96    font-size: 17px;
97  }
98
99  .list_item_description {
100   color: rgba(0,0,0,0.5);
101   font-size: 15px;
102 }
```

렌더링 및 모든 쿼리 함수로 쿼리한 후 구성 요소가 어떻게 보여야 하는지입니다:

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

## 결론

이 가이드의 끝에서, 당신은 Parse에서 기본 데이터 쿼리가 어떻게 작동하는지와 React 앱에서 Back4App으로 이를 수행하는 방법을 배웠습니다. 다음 가이드에서는 이 클래스에서 사용할 수 있는 모든 방법을 사용하여 <font color="#2166ae">`Parse.Query`</font>의 모든 잠재력을 탐구할 것입니다.
