Chapter10 Expo Module Change.
Expo init 으로 Expo App을 설치하였습니다. Expo에서 모듈의 크기가 커지자 각자의 개발성에 따라서 외부 모듈로 분리 시키는 경우가 많습니다. Nomard Coder가 설명을 한 부분이니 간략히 요점만 적고 넘어가겠습니다. 정리할 내용은 아래와 같습니다.
- Expo Font / Asset
- Theme
- Log In
- Function LogIn / LogOut
- AsyncStorage
- Context
Font 와 Asset
import { Font, Asset } from 'expo';
로 진행을 하였지만 Console에서 변경되었으니 수정하라는 내용이 나왔습니다. 수정된 내용은 아래와 같습니다.
yarn add expo-font expo-asset
import { Font } from "expo-font";
import * as Font from "expo-Asset";
Theme
테마는 우리가 앱에서 대표적으로 자주쓰는 색상과 크기 등의 스타일을 지정하여 어디에서든 접근하여 사용할 수 있도록 하기 위해서 지정하는 것입니다. 형식을 지정해 놓고 App.js에서 import하여 사용하기 위해서는 styled-component
에서 제공하는 ThemeProvider를 사용하면 됩니다.
Styles/Theme.js
export default {
bgColor: "#FAFAFA",
blackColor: "#262626",
darkGreyColor: "#003569",
lightGreyColor: "#999",
redColor: "#ED4956",
blueColor: "#3897f0"
};
App.js
import { ThemeProvider } from "styled-components";
...생략
return loaded && client && isLoggedIn !== null ? (
<ThemeProvider theme={Theme}>
<ApolloProvider client={client}>
{isLoggedIn ? <Text>i'm in</Text> : <Text>I'm out</Text>}
</ApolloProvider>
</ThemeProvider>
) : (
<AppLoading />
);
위와 같이 ThemeProvider의 속성으로 theme={Theme}를 지정하여 주고 원하는 하위 컴포넌트들을 아래에 작성하면 됩니다.
Log In
앱에서의 로그인을 Check하는 방식은 지난번 Web에서 만든 것과 비슷합니다. 다만 LocalState 대신에 AsyncStroage를 사용하는 것이 다릅니다. 먼저 코드를 한번 보겠습니다.
App.js
const [isLoggedIn, setIsLoggedIn] = useState(null);
...생략
const isLoggedIn = AsyncStorage.getItem("isLoggedIn");
console.log(isLoggedIn);
if (isLoggedIn === null || isLoggedIn === false) {
setIsLoggedIn(false);
} else {
setIsLoggedIn(true);
}
})
이렇게 useState로 isLoggedIn값을 사용하여 체크합니다. 다만 여기서 중요한것은 useState의 초기 상태를 null로 지정하는 부분과 함께 if 조건문인 isLoggedIn === null || isLoggedIn === false
이 부분이 중요합니다. isLoggedIn이 null이거나 false일 경우에 logout 상태이고 isLoggedIn이 true 일 경우에 login의 상태라고 판단하는 부분입니다.
AsyncStorage
AsyncStorage는 React-Native를 위한 Key-Value형식의 Storage입니다. 동작 방식은 Web 동작방식인 window.locaStorage와 매우 유사합니다. 다만 async-storage가 Deprecated 되었기 때문에 yarn add @react-native-community/async-storage
를 사용하여 설치하여야 합니다. 자세한 내용은 공식문서에 나와있습니다.
로그인을 하게 되면 state 값을 변경시켜 AsyncStorage의 isLoggedIn을 같이 변경시켜주어야 합니다. 따라서 useState로 setIsLoggedIn 함수로 isLoggedIn 값을 변경시켜줍니다. 다만 스마트폰에는 AsyncStorage라는 저장소가 있습니다. App의 Cache는 모두 저장하고 있기에 초기에만 Log In / Out을 판단하면 됩니다. 또한 AsyncStorage는 비동기적으로 동작하기에 Promise와 같이 await를 사용하여 함수를 작성해야 합니다.
App.js
// 로그인 로그아웃의 함수 부분입니다.
logUserOut = () => {
try {
AsyncStorage.setItem("isLoggedIn", "false");
setIsLoggedIn(false);
} catch (error) {
console.log(error);
}
};
logUserIn = () => {
try {
AsyncStorage.setItem("isLoggedIn", "true");
setIsLoggedIn(true);
} catch (error) {
console.log(error);
}
};
여기서 AsyncStorage는 항상 String 값으로 전달해 주어야 합니다. 우리가 setIsLoggedIn과 같이 Boolean 값으로 설정하면 된다고 생각하기 쉽지만 이 부분이 중요한 부분입니다. 따라서 로그인 확인을 할 때에도 String값으로 확인해야 합니다.
const isLoggedIn = await AsyncStorage.getItem("isLoggedIn");
console.log("isLoggedIn", isLoggedIn);
if (isLoggedIn === "null" || isLoggedIn === "false") {
setIsLoggedIn(false);
} else {
setIsLoggedIn(true);
}
React Context
마지막으로 트렌디한 React Context를 알아보겠습니다. 컴포넌트를 작성하고 사용하다 보면 해당 컴포넌트에서는 필요하지 않지만 하위 컴포넌트에게 전달하기 위하여 Props를 받아야 할 때가 있습니다. 이러한 패턴을 Props Drilling이라고 합니다.
Props Drilling은 서로가 서로에게 의존하는 형태로 코드가 짜여지게 되므로 재활용이 불가능하고 좋지 않는 컴포넌트를 생성하는 방식입니다. 아래의 이미지는 React Context가 무엇인지 직관적으로 보여주는 이미지입니다.

위의 이미지로 감을 잡으셨다면 React Context 사용법을 배워 봅시다. 위의 이미지처럼 React Context를 이용하면 App에서 User 컴포넌트에 Props를 전달할 수 있습니다.
App.js에서 createContext 함수로 Context라는 이름의 State를 만들어 줍니다.
해당 Context가 가지고 있는 Context.Provider 컴포넌트를 감싸줍니다.
해당 Context를 사용하고자 하는 하위 컴포넌트에서 Context.Consumer로 감싸 작성합니다.
이 때 Context.Consumer의 태그 안에는 JSX를 return하는 함수를 작성합니다.
App.js
import React, { createContext } from 'react'
const AppContext = createContext()
const App = () => {
const user = {
name: 'pacdong',
isAdmin: true
}
return (
<AppContext.Provider value={user}>
<div>
<Main />
</div>
</AppContext.Provider>
)
}
const Main = () => (
<main>
<Avatar />
</main>
)
const Avatar = () => (
<div>
<User />
</div>
)
const User = () => (
<AppContext.Consumer>
{user => {
let label = 'user'
if (user.isAdmin) {
label = 'admin'
}
return (
<div>
<div>{label}</div>
<div>{user.name}</div>
</div>
)
}}
</AppContext.Consumer>
)
즉, Context. Provider를 이용하여 Context의 변경사항을 자손들에게 제공할 수 있고, Context.Consumer로는 Context.Provider의 Value 값의 변경 사항을 가지고 와 Context에서 가장 가까운 시점의 변경 값의 Provider의 Value를 참조하여 전달합니다.
다시말해, Context는 Object로 모든 데이터를 전역에 공유할 수 있는 API입니다. 이러한 API로써 Props Drilling을 버릴 수 있도록 도와주어 분리된 컴포넌트를 만들 수 있게 합니다. 자세한 내용은 공식문서에서 확인할 수 있습니다.
Leave a comment