앞으로 React Native를 앱, 웹뷰를 웹이라 칭하겠습니다.
export default function sendMessageToWebview(
webViewRef: RefObject<WebView>,
message: {
type: string;
data: any;
},
) {
webViewRef.current?.postMessage(JSON.stringify(message));
}
webViewRef를 이용하여 웹뷰에 메시지를 전송한다.. .
<aside> ❓ webViewRef?
여기서 webViewRef는 WebView컴포넌트에 넘기는 ref객체이다.
const webViewRef = useRef(null);
// ..
return <WebView ref={webViewRef} />
</aside>
// hooks/useListenMessageToReactNative.ts
export default function useListenMessageToReactNative() {
const isapp = getIsApp();
useEffect(() => {
if (!isapp) return;
const listener = async (event: any) => {
const { type, data } = JSON.parse(event.data);
alert('test');
switch (type) {
case 'FCM_TOKEN':
postFCMToken({ token: data });
break;
case 'TOKEN': {
const { accessToken, refreshToken, userId } = data;
setTokenAtCookie({ accessToken, refreshToken, userId });
break;
}
}
};
document.addEventListener('message', listener);
window.addEventListener('message', listener);
return () => {
document.removeEventListener('message', listener);
window.removeEventListener('message', listener);
};
});
}
컴포넌트가 마운트되었을 때, 즉 클라이언트에서만 동작을 하도록 하기 위해 useEffect훅을 사용했다. document 혹은 window에 event를 추가하는 방식이기에 클라이언트에서만 동작을 해야한다.
<aside> ❓ document와 window 두 개에 event를 추가하는 이유는?
<aside> 📚 document와 window의 차이
window : 브라우저 탭에 존재하는 Javascript 전역 최상위 객체

window.을 붙이지 않고도 접근이 가능하다.document : 잠재적으로 보여질 수 있는 돔에 대한 정보가 담겨있다.

</aside>
최상위 객체가 Android 웹뷰는 document, iOS 웹뷰는 window이기 때문에, 둘 모두 추가해야한다.
</aside>
<aside> ❓ return() ⇒ {} 안에서 remove로 제거하는 이유는?
useEffect()의 콜백 함수 내부의 return함수는 컴포넌트가 언마운트될 때 실행된다. 컴포넌트가 언마운트 될 때, 추가한 event를 제거함으로써 부수 효과를 줄이기 위함이다. 계속해서 API 호출, 이벤트 리스너가 추가되면 부수효과가 생기고, 이러한 것이 계속되면 불필요한 리소스 사용이나 메모리 누수를 초래할 수 있다.
</aside>
// app/template.tsx
export default function Template({ children }) {
useListenMessageToReactNative();
return children;
}
<aside> 📚 template.js(tsx)
template.js는 layout과 유사하게 모든 layout과 페이지를 감싼다. layout과 달리 template은 자식요소마다 새로운 인스턴스를 생성한다.
useEffect, useState에 의존하는 경우 사용한다.
</aside>
훅을 layout에서 사용할 수 없다. 그렇기에, 훅을 사용할 수 있는 template.js에서 useListenMessageToReactNative을 호출한다.
const sendMessageToReactNative = ({ type, data }: SendMessageToReactNativeProps) => {
window.ReactNativeWebView &&
window.ReactNativeWebView.postMessage(
JSON.stringify({
data,
type,
})
);
};
export default sendMessageToReactNative;