728x90
반응형
안녕하세요 오늘은 리액트 네이티브를 사용한 간단한 앱에서 로그인,회원가입 기능을 구현하여보겠습니다.
저번과 다른점은 타입스크립트로 변경하였고
상태관리를 위해 recoil을 적용하였습니다.
일단 프로젝트의 구조를 먼저 살펴보겠습니다.
저번에 추가하여 회원가입 스크린을 만들고 리코일 아톰을 추가하였습니다.
먼저 auth.ts입니다.
import { atom } from "recoil";
import axios from "axios";
import AsyncStorage from "@react-native-async-storage/async-storage";
import instance from "../../axios/AxiosInstance";
interface User {
username: string;
userId: string;
token?: string;
}
export const userState = atom<User>({
key: "user",
default: { username: "", userId: "" }
});
export const isLoggedInState = atom<boolean>({
key: "isLoggedIn",
default: false
});
export const updateLoginStatus = async () => {
const token = await AsyncStorage.getItem("token");
return token ? true : false;
};
export const updateAccessToken = async (refreshToken: string) => {
const response: any = await axios.post(
"http://localhost:8093/api/update-token",
{ refreshToken }
);
const newAccessToken = response.data.accessToken;
await AsyncStorage.setItem("token", newAccessToken);
return newAccessToken;
};
export const login = async (formData: { userId: string; password: string }) => {
const response = await axios.post(
"http://localhost:8093/api/login",
formData
);
const { username, userId, token, refreshToken } = response.data;
console.log("Login response userId:", userId); // 응답으로 받은 userId 확인
await AsyncStorage.setItem("token", token); // 로컬 스토리지에 토큰 저장
await AsyncStorage.setItem("userId", userId); // 로컬 스토리지에 userId 저장
await AsyncStorage.setItem("refreshToken", refreshToken); // 로컬 스토리지에 리프레쉬 토큰 저장
return { username, userId, token, refreshToken };
};
export const signup = async (formData: {
username: string;
userId: string;
password: string;
}) => {
const response = await axios.post(
"http://localhost:8093/api/signup",
formData
);
const { username, userId, token, refreshToken } = response.data;
await AsyncStorage.setItem("token", token); // 로컬 스토리지에 토큰 저장
await AsyncStorage.setItem("userId", userId); // 로컬 스토리지에 userId 저장
await AsyncStorage.setItem("refreshToken", refreshToken); // 로컬 스토리지에 리프레쉬 토큰 저장
return { username, userId, token, refreshToken };
};
export const logout = async () => {
try {
await axios.post("http://localhost:8093/api/logout");
// 로컬 스토리지에서 토큰 제거
await AsyncStorage.removeItem("token");
await AsyncStorage.removeItem("refreshToken");
await AsyncStorage.removeItem("userId"); // 로컬 스토리지에서 userId 제거
} catch (error) {
console.error("Error during logout:", error);
}
};
백엔드 api에서 받은 토큰들을 AsyncStorage 에 저장하여 관리합니다.
다음은 새로 추가한 회원가입 창입니다.
import React, { useState } from "react";
import { StyleSheet, Text, View, Button, TextInput } from "react-native";
import { StackNavigationProp } from "@react-navigation/stack";
import { RootStackParamList } from "../App";
import { signup } from "../recoil/atoms/auth"; // 실제 파일 경로로 수정해주세요.
import { useSetRecoilState } from "recoil";
import { userState, isLoggedInState } from "../recoil/atoms/auth"; // userState와 isLoggedInState를 정의한 파일 경로로 수정해주세요.
type SignupScreenNavigationProp = StackNavigationProp<
RootStackParamList,
"Register"
>;
type Props = {
navigation: SignupScreenNavigationProp;
};
const SignupScreen: React.FC<Props> = ({ navigation }) => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [userId, setUserId] = useState("");
const setUser = useSetRecoilState(userState);
const setIsLoggedIn = useSetRecoilState(isLoggedInState);
const handleSignup = async () => {
// 회원가입 API 호출 및 회원가입 로직 처리
try {
const {
username: loggedInUsername,
userId: loggedInUserId,
token
} = await signup({ username, userId, password });
setUser({ username: loggedInUsername, userId: loggedInUserId, token });
setIsLoggedIn(true);
console.log(`Signup successful for userId: ${loggedInUserId}`);
// 여기서 사용자를 다음 화면(예: 메인 화면)으로 이동시킬 수 있습니다.
navigation.navigate("Home");
} catch (error) {
console.error("Error during signup:", error);
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Sign Up</Text>
<TextInput
style={styles.input}
placeholder="Username"
value={username}
onChangeText={setUsername}
/>
<TextInput
style={styles.input}
placeholder="Password"
secureTextEntry
value={password}
onChangeText={setPassword}
/>
<TextInput
style={styles.input}
placeholder="UserId"
value={userId}
onChangeText={setUserId}
/>
<Button title="Sign Up" onPress={handleSignup} />
<Button
title="Back to Login"
onPress={() => navigation.navigate("Login")}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center"
},
title: {
fontSize: 24,
marginBottom: 20
},
input: {
width: "80%",
padding: 10,
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 5,
marginBottom: 10
}
});
export default SignupScreen;
리액트 네이티브를 사용하니까 앱도 웹과 유사하게 코드를 작성할 수 있어
편했습니다.
깃헙 주소 첨부합니다.https://github.com/muganghskim/nativeTest
localhost로 api 요청 시 네트워크 에러가 발생하였는데 정확한 ip 주소를 입력하여 에러를 해결하였습니다.
리프레쉬 토큰을 사용하여 로그인을 유지시키는 방법은 아직 미구현하였습니다.
감사합니다.
728x90
반응형
'리액트' 카테고리의 다른 글
리액트 아토믹 디자인(Atomic Design)에 대해 알아보자 (0) | 2023.09.12 |
---|---|
React에서 styled-components로 스타일링하기 (0) | 2023.09.08 |
리액트 네이티브와 Expo로 아이폰 앱 만들기: 홈 화면과 로그인 화면 구현 (0) | 2023.08.03 |
useEffect를 사용하여 api를 사용해보자 (0) | 2023.03.21 |
리액트 useState에 대해 알아보자 (0) | 2023.03.21 |
댓글