---
title: React Native에서 GraphQL로 로그인 구현하기
slug: docs-kr/react-native/graphql/users/react-native-login-sample
description: Relay와 GraphQL을 사용해 React Native 앱에 사용자 로그인 구현 방법 배우기.
image: https://www.back4app.com/images/logo-social.png
createdAt: 2024-03-20T13:25:16.408Z
---

# Relay를 사용한 React Native 로그인 샘플

## 소개

지난 튜토리얼에서는 Back4App과 Relay를 사용하여 React Native 앱에 사용자 가입 기능을 구현했습니다. 이 가이드에서는 앱 인증 기능을 보완하는 로그인 메커니즘을 구축할 것입니다.

아시다시피, Parse는 기본적으로 사용자 클래스인 User를 제공하며, 이는 앱에 필요할 때 사용자를 로그인시키기 위한 준비된 GraphQL 뮤테이션을 이미 가지고 있습니다.

여기서의 흐름은 사용자 가입 튜토리얼과 매우 유사할 것입니다. formik을 사용하여 로그인 화면을 구축한 다음, 이 양식이 Relay 뮤테이션을 호출할 것입니다. Relay 뮤테이션은 인증 프로세스를 처리하는 Back4App 서버와 통신할 것입니다.

:::hint{type="success"}
**언제든지 이 프로젝트에 대한 액세스는 GitHub 리포지토리를 통해 스타일과 전체 코드를 확인할 수 있습니다.**

- [JavaScript 예제 리포지토리](https://github.com/templates-back4app/react-native-graphql-relay-js-users)
:::

## 목표

이 가이드의 끝에서, 아래와 같이 사용자 로그인 기능이 구현된 React Native 애플리케이션을 갖게 될 것입니다.

### 전제 조건

:::hint{type="info"}
- Parse Server 버전 3.10 이상을 사용하여 Back4App에서 생성된 앱.
- 다음의 [Relay 환경 설정 튜토리얼](https://www.back4app.com/docs/react-native/graphql/relay-setup):
- 간단한 로그인 양식이 있는 앱을 기대하세요. 여기서는 사용자 이름과 비밀번호가 있는 양식을 가진 Expo 앱을 사용하고 있습니다.
- 이 튜토리얼에서는 React Native 프레임워크로 Expo를 사용할 것입니다;
- 이 튜토리얼에서는 기본 구현 언어로 Javascript를 사용할 것입니다;
- 이 튜토리얼에서는 우리의 스타일 CSS 샘플을 사용할 것입니다;
:::

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/HLS0YNmG6UzTVGL_mVB82_image.png" size="60" width="828" height="1792" position="center" showCaption="false"}

## 1 - 로그인 폼 만들기

애플리케이션에 이미 Form 컴포넌트가 있다면 2단계로 넘어가세요. 그렇지 않다면, 우리의 보일러플레이트를 따라 하셔도 좋습니다. 이 폼은 회원가입 문서에서 사용된 폼과 유사합니다. 로그인용으로도 사용할 수 있습니다. 구현 방법을 배우고 싶다면 사용자 [사용자 가입](https://www.back4app.com/docs/react-native/graphql/user-sign-up-relay)을 참조하세요. 로그인 폼 코드는 다음과 같아야 합니다:

```javascript
1	import React, {useState} from 'react';
2	import environment from '../../relay/environment';
3	import {FormikProvider, useFormik} from 'formik';
4	import { Button, Text, TextInput, View, TouchableOpacity } from 'react-native';
5	import Styles from "../../Style"
6	
7	const SignIn = () => {
8	  const [userLogged, setUserLogged] = useState(null);
9	
10	  const onSubmit = async (values) => {
11	    // @todo the mutation will be implemented here
12	  };
13	
14	  const formikbag = useFormik({
15	    initialValues: {
16	      username: '',
17	      password: '',
18	    },
19	    onSubmit,
20	  });
21	
22	  const {handleSubmit, setFieldValue} = formikbag;
23	
24	  if (userLogged?.id) {
25	    return (
26	      <View style={ {marginTop: 15, alignItems: 'center'} }>
27	        <Text>User {userLogged.name} logged</Text>
28	      </View>
29	    );
30	  }
31	
32	  return (
33	    <FormikProvider value={formikbag}>
34	        <View style={Styles.login_wrapper}>
35	            <View style={Styles.form}>
36	                <Text>Username</Text>
37	                <TextInput
38	                    name={"username"}
39	                    style={Styles.form_input}
40	                    autoCapitalize="none"
41	                    onChangeText={(text) => setFieldValue("username", text)}
42	                />
43	                <Text>Password</Text>
44	                <TextInput
45	                    style={Styles.form_input}
46	                    name={"password"}
47	                    autoCapitalize="none"
48	                    secureTextEntry
49	                    onChangeText={(text) => setFieldValue("password", text)}
50	                />
51	                <TouchableOpacity onPress={() => handleSubmit()}>
52	                    <View style={Styles.button}>
53	                        <Text style={Styles.button_label}>{"Sign in"}</Text>
54	                    </View>
55	                </TouchableOpacity>
56	            </View>
57	        </View>
58	    </FormikProvider>
59	  );
60	};
61	
62	export default SignIn;
```

애플리케이션을 실행하면 아래와 같은 화면이 표시됩니다.

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/xp1JZ8tdTWLrt9vgHL6TX_image.png" size="60" width="828" height="1792" position="center" showCaption="false"}

onSubmit 함수에 주목하세요. Relay Mutation이 이 함수 안에 있을 것임을 유의하세요. 애플리케이션이 Formik을 사용하지 않더라도 문제는 없습니다. Form Component를 구현할 때, Relay Mutation은 submit 함수 안에서만 호출되면 됩니다.

## 2 - 뮤테이션 생성하기

Colocation 원칙을 사용하여 Form Component와 가장 가까운 mutations라는 새 폴더를 생성합시다. colocation에 대해 더 알고 싶다면 [시작하기](https://www.back4app.com/docs/react-native/graphql/get-started-relay-graphql) 가이드를 참조하세요.

아래 이미지에서 colocation 원칙이 실제로 어떻게 적용되는지 볼 수 있습니다. 컴포넌트와 관련된 모든 것이 그 근처에 있습니다. LogIn 컴포넌트를 감싸는 폴더가 있으며, 그 안에 mutations라는 또 다른 폴더를 생성합니다. mutations 폴더 안에 Relay Mutation을 생성할 것입니다.

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/Lm6WApFKYgSa8kzB7Wqaj_image.png" size="80" width="290" height="100" position="center" showCaption="false"}

:::hint{type="success"}
이 패턴은 큰 프로젝트에서 완벽하게 작동합니다. 새로운 변형이 생길 때마다 그것을 사용할 구성 요소에 가깝게 두십시오.
:::

이 폴더 안에 <font color="#2166ae">`LogInMutation.js`</font>라는 새 파일을 만듭니다. Relay 변형을 설명한 사용자 작업 가이드에 따라, 아래와 같이 커밋 함수를 생성합니다.

```javascript
1	function commit({ environment, input, onCompleted, onError }) {
2	  const variables = { input };
3	
4	  commitMutation(environment, {
5	    mutation,
6	    variables,
7	    onCompleted,
8	    onError,
9	  });
10	}
11	
12	export default {
13	  commit,
14	};
```

양식 구성 요소로 돌아가기 전에, 변형을 나타내는 GraphQL 조각을 받을 변수를 생성합시다. GraphQL 조각은 Relay 컴파일러가 읽고 schema.graphql과 일치시킬 것입니다.

commitMutation 전에 다음 코드를 복사하여 붙여넣으십시오:

```javascript
1	const mutation = graphql`
2	  mutation LogInMutation($input: LogInInput!) {
3	    logIn(input: $input) {
4	      viewer {
5	        user {
6	          id
7	          username
8	          createdAt
9	        }
10	        sessionToken
11	      }
12	    }
13	  }
14	`;
```

최종 파일:

```javascript
1	import { commitMutation, graphql } from 'react-relay';
2	
3	const mutation = graphql`
4	  mutation LogInMutation($input: LogInInput!) {
5	    logIn(input: $input) {
6	      viewer {
7	        user {
8	          id
9	          createdAt
10	          updatedAt
11	          username
12	        }
13	        sessionToken
14	      }
15	    }
16	  }
17	`;
18	
19	function commit({ environment, input, onCompleted, onError }) {
20	  const variables = { input };
21	
22	  commitMutation(environment, {
23	    mutation,
24	    variables,
25	    onCompleted,
26	    onError,
27	  });
28	}
29	
30	export default {
31	  commit,
32	};
```

:::hint{type="success"}
GraphQL 프래그먼트가 백엔드를 나타내므로, Relay Mutation의 코드를 얻으려면 [Back4App GraphQL 요리책](https://www.back4app.com/docs/react-native/graphql/users/back4app.com/docs/parse-graphql/graphql-sign-in)으로 가서 프래그먼트를 찾을 수 있습니다.
:::

새로운 뮤테이션을 생성하고 파일을 업데이트하려면 <font color="#2166ae">`yarn relay`</font>를 실행하세요. 모든 것이 괜찮다면 뮤테이션의 유형이 생성되고 진행할 수 있습니다.

## 3 - 제출 함수 구현

제출 단계는 가장 중요합니다. 여기서 Relay Mutation의 마법이 일어납니다.

:::hint{type="info"}
이 단계는 formik에서 양식의 값을 가져옵니다. 애플리케이션이 formik을 사용하지 않는 경우, 값은 그들이 얻는 방식과 관계없이 여기에서 사용 가능해야 합니다.
:::

폼 컴포넌트로 돌아가서, 릴레이 뮤테이션의 구현을 시작해 보겠습니다.

뮤테이션 가져오기

```javascript
1	import LogInMutation from './mutations/LogInMutation';
```

OnSubmit 함수 내부에서 입력 변수를 생성하기 시작합니다:

```javascript
1	const onSubmit = (values) => {
2	    const {username, password} = values;
3	    const input = {
4	        username,
5	        password,
6	    };
7	}
```

:::hint{type="info"}
값은 Formik에 의해 주입됩니다. 여기서 formik을 사용하지 않는 경우, 값은 아마도 폼의 기본 oSubmit을 통해 오거나 원하는 대로 올 것입니다.
:::

마지막으로, 모든 props를 전달하여 뮤테이션을 호출합니다(가져오는 것을 잊지 마세요).

```javascript
1	    LogInMutation.commit({
2	      environment,
3	      input,
4	      onCompleted: (response) => {
5	        if(!response?.logIn || response?.logIn === null) {
6	          alert('Error while logging');
7	          return;
8	        }
9	
10	        const { viewer } = response?.logIn;
11	        const { sessionToken, user } = viewer;
12	
13	        if (sessionToken !== null) {
14	          setUserLogged(user);
15	          alert(`user ${user.username} successfully logged`);
16	          return;
17	        }
18	      },
19	      onError: (errors) => {
20	        alert(errors[0].message);
21	      },
22	    });
```

onSubmit의 최종 결과

```javascript
1	const onSubmit = (values) => {
2	    const { username, password } = values;
3	    
4	    const input = {
5	      username,
6	      password,
7	    };
8	
9	    LogInMutation.commit({
10	      environment,
11	      input,
12	      onCompleted: (response) => {
13	        if(!response?.logIn || response?.logIn === null) {
14	          alert('Error while logging');
15	          return;
16	        }
17	
18	        const { viewer } = response?.logIn;
19	        const { sessionToken, user } = viewer;
20	
21	        if (sessionToken !== null) {
22	          setUserLogged(user);
23	          alert(`user ${user.username} successfully logged`);
24	          return;
25	        }
26	      },
27	      onError: (errors) => {
28	        alert(errors[0].message);
29	      },
30	    });
31	};
```

프로젝트를 실행하고, 사용자를 등록한 후 Back4App 대시보드에서 확인하세요. 뮤테이션은 서버에서 값을 반환합니다. 세션 토큰이 반환되면 애플리케이션은 이를 관리할 수 있습니다.

지난 튜토리얼에서 생성한 사용자를 사용하여 테스트합니다. 모든 것이 정상적으로 작동하면 아래와 같은 알림이 표시됩니다:

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/0_SLXED_VK1LnAADDzUuy_image.png" size="70" width="828" height="1792" position="center" showCaption="false"}

## 오류 처리

커밋 변이에서 애플리케이션은 onError에서 오류를 처리할 수 있습니다. 항상 오류 배열을 수신합니다. 가장 일반적인 경우는 이 배열에 오류 메시지를 포함하는 객체가 하나만 있는 것입니다. 아래 예제를 참조하세요:

:::BlockQuote
1	\{
2	  "errors": \[
3	    \{
4	      "message": "유효하지 않은 사용자 이름/비밀번호입니다.",
5	      "locations": \[
6	        \{
7	          "line": 2,
8	          "column": 3
9	        }
10	      ],
11	      "path": \[
12	        "logIn"
13	      ],
14	      "extensions": \{
15	        "code": 202
16	      }
17	    }
18	  ],
19	  "data": \{
20	    "logIn": null
21	  }
22	}
:::

이 예제를 바탕으로 자유롭게 오류 처리를 생성하세요. 지금까지 어떤 오류가 반환되면 우리는 단순히 경고로 표시합니다:

```javascript
1   onError: (errors) => {
2     alert(errors[0].message);
3   },
```

## 결론

이제 완전히 작동하는 로그인 기능이 있는 애플리케이션을 갖게 되었습니다. 다음 가이드에서는 동일한 접근 방식을 사용하여 로그아웃하는 방법을 이해하게 될 것입니다. 또한 Relay 변이를 사용하여 백엔드를 호출할 것입니다.
