๋๋ ํ์ฌ์์ ์ฑ์ ๊ฐ๋ฐํ๊ณ ์๋ค. ๋ณดํต ์ฑ ๊ฐ๋ฐ์ ํ๋ค๊ณ ํ๋ฉด React Native, flutter, swift, kotlin์ ์ฌ์ฉํด์ ๊ฐ๋ฐํ ๊ฑฐ๋ผ๊ณ ์๊ฐํ์ง๋ง ๋๋ Next.js๋ก ๊ฐ๋ฐํ๊ณ ๊ฐ๋ฐํ ํ๋ฉด์ react-native ์น๋ทฐ๋ก ๋์์ ๋ณด์ฌ์ฃผ๋ ๋ฐฉ์์ผ๋ก ๊ฐ๋ฐํ๊ณ ์๋ค.
์ฒ์์๋ ์น๋ทฐ๋ฅผ ํตํ ๊ฐ๋ฐ ๋ฐฉ์์ด ์ฝ๊ฒ ์ดํด๊ฐ์ง ์์์๋๋ฐ ์ด์ ๋ ์ต์ํด์ง๊ธฐ๋ ํ๊ณ ํน์ ์์ ์ ๋์ฒ๋ผ ์น๋ทฐ ๊ฐ๋ฐ์ ๋ํด์ ๊ถ๊ธํ๊ฑฐ๋ ์ด๋ ค์ด ์ฌ๋๋ค์ ์ํด์ ์ ๋ฆฌํด๋ณด๊ณ ์ ํ๋ค! โจ
์น๋ทฐ๋ ๋ชจ๋ฐ์ผ ์ดํ๋ฆฌ์ผ์ด์ ์์ ์น ์ฝํ ์ธ (์น ํ์ด์ง)๋ฅผ ํ์ํ๋ ์ปดํฌ๋ํธ์ด๋ค. ๋ค์ดํฐ๋ธ ์ฑ ๋ด๋ถ์ HTML, CSS, Javascript ๋ก ์์ฑ๋ ์น ํ์ด์ง๋ฅผ ๋ ๋๋งํ๋ ๋ฐฉ์์ผ๋ก ์ฃผ๋ก ๋ค์ดํฐ๋ธ์ ์น์ ํผํฉํ ํ์ด๋ธ๋ฆฌ๋ ์ฑ์์ ๋ง์ด ์ฌ์ฉ๋๋ค.
์ฐ๋ฆฌ ํ์ฌ๊ฐ์ ๊ฒฝ์ฐ์๋ ์ฑ ๋ด๋ถ์ ๋ชจ๋ ํ์ด์ง ๋ฐ ๊ธฐ๋ฅ๋ค์ Next.js๋ก ๊ฐ๋ฐํ๊ณ ์๋ค. ์ฆ, ๊ฐ๋ฐ ๋ฐฉ์์ ์น ๊ฐ๋ฐ๊ณผ ๋์ผํ๋ฉฐ Next.js๋ก ๊ฐ๋ฐํ ์นํ์ด์ง๋ฅผ(URL) ์น๋ทฐ๋ฅผ ํตํด ๋ณด์ฌ์ค๋ค.
react-native์์ ์น๋ทฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ react-native-webview ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํ๋ค.
react-native ์ด๊ธฐ ๋ฒ์ ์๋ WebView ๊ฐ ๋ด์ฅ๋ ์ปดํฌ๋ํธ์์ผ๋, ํ์ฌ๋ ๋ณ๋์ ํจํค์ง๋ก ๋ถ๋ฆฌ๋์ด react-native-webview ๋ผ๋ ์ด๋ฆ์ผ๋ก ์ ๊ณต๋๊ณ ์๋ค.
์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด์ ์น ํ์ด์ง์ ๋ค์ดํฐ๋ธ ์ฑ ๊ฐ์ ํต์ ๊ณผ ์ํธ์์ฉ์ ๊ด๋ฆฌํ ์ ์๋ค. ๊ฐ๋จํ ์์ ์ฝ๋๋ฅผ ํตํด ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ์ดํด๋ณด์.
WebView ์ปดํฌ๋ํธ์์ ์ ๊ณตํ๋ ์ต์ ์ ๋งค์ฐ ๋ง์ง๋ง ๊ฐ์ฅ ๊ธฐ๋ณธ์ผ๋ก ์๊ณ ์์ด์ผ ํ๋ ๋๊ฐ์ง ์ ๋๋ง ์๊ฐํ๋ ค๊ณ ํ๋ค.
import React from 'react';
import { WebView } from 'react-native-webview';
const MyWebView = () => {
const handleMessage = (event) => {
alert("Message from WebView: " + event.nativeEvent.data);
};
return (
<WebView
source={{ uri: "https://example.com" }}
onMessage={handleMessage}
/>
);
};
export default MyWebView;
์น์์๋ ์ ๊ณตํ์ง ์๋ ์ฑ์์๋ง ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ ํ์ํ ๋ ์น๋ทฐ ํต์ ์ ํ๋ค. ๋ด๊ฐ ๊ฒฝํํ๋ ๊ฒ์ ์๋ก ๋ค์๋ฉด ๋ชจ๋ฌ์์ ํํ ๋ณผ ์ ์๋ 1์ผ ๋์ ๋ณด์ง ์๊ธฐ
, ์๋ฆผ ์ค์ ํ์ฉ/๊ฑฐ๋ถ
๋ฑ ์ฌ๋ฌ๊ฐ์ง ๊ธฐ๋ฅ์ด ์กด์ฌํ๋ค. ์ด๋ฐ ๊ธฐ๋ฅ๋ค์ ์ผ๋ฐ์ ์ธ ์น ํ์ด์ง์์๋ ๊ตฌํํ ์ ์๊ณ ๋ค์ดํฐ๋ธ ๊ธฐ๋ฅ์ ์ง์ ํ์ฉํด์ผํ๊ธฐ ๋๋ฌธ์ ๋ค์ดํฐ๋ธ ์ฝ๋์์ ์ฒ๋ฆฌํ ํ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์น ํ์ด์ง๋ก ๋ค์ ์ ๋ฌํด์ผํ๋ค.
์ด๋ฐ ๋ค์ดํฐ๋ธ ๊ธฐ๋ฅ์ ์ค์ ๋๋ฐ์ด์ค๋ ์๋ฎฌ๋ ์ดํฐ์์๋ง ํ์ธํ ์ ์๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐ ์ค์๋ ์๋ฎฌ๋ ์ดํฐ๋ฅผ ํตํด ํ ์คํธ๋ฅผ ์งํํ๋ฉฐ ํต์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ด๋ฃจ์ด์ง๋์ง ํ์ธํ๋ ๊ฒ์ด ์ค์ํ๋ค.
์น๋ทฐ ํต์ ์ ํ ๋๋ ์์์ ์ธ๊ธํ๋ react-native-webview๋ฅผ ํตํด์ ํ ์ ์๋ค. ์ดํด๋ฅผ ๋๊ธฐ ์ํด์ ์์ธํ ์์๋ฅผ ์ดํด๋ณด๋๋ก ํ์.
asyncStorage ๋ ๋ด๊ฐ ์น๋ทฐ ํต์ ์์ ๊ฐ์ฅ ์์ฃผ ์ฌ์ฉํ๋ ๊ธฐ๋ฅ์ด๋ค. ์ด๋ฆ๋ถํฐ ๊ฐ์ด ์ค๊ฒ ์ง๋ง ์น์์์ localStorage์ ๊ฐ์ ์ญํ ์ ํ๋ค๊ณ ์๊ฐํ๋ฉด ๋๋ค.
์น์์ ํด๋ผ์ด์ธํธ๋จ์์ ์ด๋ ํ ์ ๋ณด๋ฅผ ์์๋ก ์ ์ฅํด์ผํ ๋ ์ฌ์ฉํ๋ ๊ณณ์ด localStorage์ธ๋ฐ ์ฑ์์๋ ์ด๋ ํ ์ ๋ณด๋ฅผ ๋๋ฐ์ด์ค์ ์ ์ฅํด์ผํ ๋ ์ฌ์ฉํ๋ ๊ฒ์ด asyncStorage์ด๋ค.
localStorage ์ฒ๋ผ Key ์ value ๊ฐ์ผ๋ก ์ด๋ฃจ์ด์ ธ ์ ์ฅํ๊ณ ์์ ํ๊ณ ์ญ์ ํ ์ ์๋ค.
asyncStorage๊ฐ ํ์ํ ๊ฒฝ์ฐ๋ ๋ค์ํ์ง๋ง ๋ํ์ ์ผ๋ก ๋ค์ ๋ณด์ง ์๊ธฐ
๊ฐ ์๋ค.
์ดํด๋ฅผ ๋๊ธฐ์ํ ์์ ์ฝ๋๋ก ์๋ต๋ ๋ถ๋ถ์ด ์์ ์ ์์ผ๋ ์ด ์ ์ฐธ๊ณ ํด์ฃผ์ธ์
// Next.js
const EventModal = () => {
// react native ๋ก ๋ฉ์ธ์ง ์ ์ก
const handleClickClose = () => {
window.ReactNativeWebView.postMessage("hideOneDay")
}
return (
<div>
...
<button onClick={handleClickClose}>๋ค์ ๋ณด์ง ์๊ธฐ</button>
</div>
)
}
export default EventModal
window.ReactNativeWebView.postMessage("hideOneDay")
๋ฅผ ํธ์ถํ์ฌ, ์น ํ์ด์ง์์ React Native ์น๋ทฐ๋ก "hideOneDay"๋ผ๋ ๋ฉ์ธ์ง๋ฅผ ์ ๋ฌํ๋ค.// React Native
import { WebView } from 'react-native-webview';
import AsyncStorage from '@react-native-async-storage/async-storage';
const App = () => {
// ์น๋ทฐ์์ ๋ฐ์ ๋ฉ์์ง ์ฒ๋ฆฌ
const handleMessage = async (event) => {
const message = event.nativeEvent.data;
if (message === "hideOneDay") {
try {
// AsyncStorage์ ๋ฐ์ดํฐ ์ ์ฅ
await AsyncStorage.setItem("hideOneDay", "true");
alert("๋ชจ๋ฌ์ ๋ค์ ๋ณด์ง ์๋๋ก ์ค์ ์ด ์๋ฃ๋์์ต๋๋ค.");
} catch (error) {
console.error("Error saving data to AsyncStorage", error);
}
}
};
return (
<WebView
source={{ uri: "https://example.com"}}
onMessage={handleMessage}
/>
)
}
export default App
event.nativeEvent.data
๋ฅผ ํตํด ์์ ๋ ๋ฉ์์ง๋ฅผ ํ์ธํ๊ณ , ๋ฉ์์ง๊ฐ "hideOneDay"์ผ ๋, AsyncStorage์ "hideOneDay" ํค๋ก "true" ๊ฐ์ ์ ์ฅํ๊ฒ ๋๋ค.// React Native
import { WebView } from 'react-native-webview';
import AsyncStorage from '@react-native-async-storage/async-storage';
const App = () => {
const webViewRef = useRef(null);
...
// ์ ์ฅ๋ ๋ฐ์ดํฐ ๋ถ๋ฌ์ ์น๋ทฐ๋ก ์ ์ก
useEffect(() => {
const checkAsyncStorage = async () => {
try {
const hideOneDay = await AsyncStorage.getItem("hideOneDay");
if (hideOneDay === 'true' && webViewRef.current) {
// ์ ์ฅ๋ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด ์น๋ทฐ๋ก ๋ฉ์์ง ์ ์ก
webViewRef.current.postMessage("hideModal");
}
} catch (error) {
console.error('Error retrieving data from AsyncStorage', error);
}
};
checkAsyncStorage();
}, [])
return (
<WebView
ref={webViewRef}
source={{ uri: "https://example.com"}}
onMessage={handleMessage}
/>
)
}
export default App
webViewRef.current.postMessage("hideModal")
๋ก ํธ์ถํ์ฌ ์น๋ทฐ๋ก "hideModal" ์ ์ ์กํ๋ฉฐ ์ด๋ฅผ ํตํด ์น ํ์ด์ง์์ ๋ชจ๋ฌ์ ์จ๊ธธ ์ ์๋ค.
import EventModal from "./EventModal"
const Home = () => {
// ๋ชจ๋ฌ์ ํ์ ์ฌ๋ถ๋ฅผ ์ํ๋ก ๊ด๋ฆฌ
const [isModalVisible, setModalVisible] = useState(true);
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
// ๋ฉ์์ง ๋ด์ฉ ํ์ธ
if (event.data === "hideModal") {
// ๋ชจ๋ฌ ์จ๊ธฐ๊ธฐ
setModalVisible(false);
}
};
// ๋ฉ์์ง ์ด๋ฒคํธ ๋ฆฌ์ค๋ ๋ฑ๋ก
window.addEventListener("message", handleMessage);
// ์ปดํฌ๋ํธ ์ธ๋ง์ดํธ ์ ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ ๊ฑฐ
return () => {
window.removeEventListener("message", handleMessage);
};
}, []);
return (
<div>
{isModalVisible && <EventModal />}
<h1>๋ฉ์ธ ํ์ด์ง</h1>
</div>
)
}
export default Home
window.addEventListener("message", handleMessage)
๋ฅผ ํธ์ถํ๊ณ handleMessage ํจ์๋ฅผ ํตํด "hideModal" ๋ฉ์ธ์ง๋ฅผ ๋ฐ์ผ๋ฉด isModalVisible ์ํ๊ฐ์ ์
๋ฐ์ดํธ ์์ผ ๋ชจ๋ฌ์ ์จ๊ธด๋ค.์ ์ฌํ๊ณ ๊ฐ์ด ์ทจ์ ์ ์ค๋นํ๋ ๋๊ธฐ๋ค์ ๋ง๋๋ฉด "ํ์ฌ์์ ์ด๋ค ์ผ์ ํ๊ณ ์์ด์?"๊ฐ ๊ฐ์ฅ ๋ง์ด ๋ฃ๋ ์ง๋ฌธ์ด์๋ค. ๊ทธ๋ฆฌ๊ณ ์ฑ ๊ฐ๋ฐ์ ํ๋ค๊ณ ํ๋ฉด "React Native ์ฌ์ฉํ์๋์?"๋ผ๊ณ ๋ฌผ์ด๋ณด์๋๋ฐ, ์ด๋๋ง๋ค ๋๊ฐ(?)ํ ๋๊ฐ ์์๋ค. ์๋ํ๋ฉด ์ฐ๋ฆฌ ์ฑ์ React Native๋ก ๋์ด์๊ธด ํ์ง๋ง ๊ทธ๋ ๋๋ React Native๋ฅผ ์ ํ ๋ง์ง์ง ์๊ณ ์์๊ณ Next.js๋ก๋ง ๊ฐ๋ฐํ๊ณ ์์๊ธฐ ๋๋ฌธ์ด๋ค.
์๊ฐํด๋ณด๋ฉด ๊ทธ๋ ๋๋ ์น๋ทฐ ๊ฐ๋ฐ์ ๋ํด ์ ๋๋ก ์ดํดํ๊ณ ์์ง ๋ชปํด์ ๋จ์๊ฒ ์ค๋ช ํ๋ ๋ฐ ์์ ์ด ์์๋ ๊ฒ ๊ฐ๋ค. ํ์ง๋ง ์ธ์ ๋ ๊ทธ๋ ๋ฏ ๋ง์ ๊ฒช์ด๋ณด๋ฉด ๋ณ๊ฑฐ ์๊ณ ์ต์ํด์ง๊ธฐ ๋ง๋ จ์ด๋ค. 2๋ ์ฐจ ๊ฐ๋ฐ์๊ฐ ๋ ์ง๊ธ์ ์น๋ทฐ ์ฑ ๊ฐ๋ฐ์ ๋ํด ๋๊ฐ ๋ฌผ์ด๋ณธ๋ค๋ฉด ์์ธํ๊ฒ ์ค๋ช ํด์ค ์ ์๋ค. ๊ทธ๋์ ํน์ ์น๋ทฐ ๊ฐ๋ฐ์ ์ด์ ๋ง ์์ํ๊ฑฐ๋ ๊ถ๊ธ์ฆ์ ๊ฐ์ง ๋ถ๋ค์๊ฒ ๋์์ด ๋์์ผ๋ฉด ์ข๊ฒ ๋ค๋ ๋ง์์ผ๋ก ์ด ๊ธ์ ์ฐ๊ฒ ๋๋ค.
๋ฌผ๋ก ๊ธ์ ์ ๋ฆฌํ๋ฉด์ ๋๋ ์น๋ทฐ์ ๋ํด ๋ค์ ํ ๋ฒ ์ ๋ฆฌํ๊ฒ ๋์ด ์ข์๋ค. ์ด๋์ ๋ธ๋ก๊ทธ๋ฅผ ๊พธ์คํ ์จ์ผ ํ๋๋ณด๋คใ ใ ๊ธฐ๋ก์ ์ค์์ฑ!
์ฌ์ค ํ์ฌ ์ฝ๋์์ ๋ด๊ฐ ์ฌ์ฉํ ๋ถ๋ถ์ ์์ ๋ก ๊ฐ์ ธ์ค๊ณ ์ถ์๋๋ฐ, ํ์ฌ ์ฝ๋์์๋ sendMessage ๋ถ๋ถ(RN ํต์ )์ lib ํด๋์ ๋ชจ๋ํํด์ ์ฌ์ฉํ๊ณ ์์ด์ ๋ด๊ฐ ์๊ฐํ๊ณ ์ถ์๋ ๋ถ๋ถ ์ธ์๋ ๋ณต์กํ ๋ถ๋ถ์ด ๋ง์ ์ง์ ์์ ์ฝ๋๋ฅผ ๋ง๋ค์๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ RN ํต์ ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ํด์๋ง ์๊ฐํ๋ ค๊ณ ํ๊ธฐ ๋๋ฌธ์ ๋๋ฌด ๋ฅํ ๋ด์ฉ์ ์ต๋ํ ๋์ด๋ด๋ ค๊ณ ํ๋ค. RN ํต์ ์ ์ฌํ ๋ฒ์ ์ ๋ค์ ํฌ์คํ ์์ ๋ค๋ค์ผ๊ฒ ๋ค.
๊ฐ์ฌํฉ๋๋ค ์ ๋ฆฌ๋ฅผ ์ ๋ง ์ํ์๋ค์ !