๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ป ํ”„๋ก ํŠธ์—”๋“œ

React Native - ์›น๋ทฐ ํ†ต์‹  ๊ตฌํ˜„(TypeScript)

by megan07 2024. 1. 27.

์šฐ์„  React Native์—์„œ ์›น๋ทฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ

react-native-webivew ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

 

  RN Webview
๋ฉ”์‹œ์ง€ ๋ณด๋‚ผ ๋•Œ webviewRef.current.postMessage(JSON.stringify(message)); window.ReactNativeWebView?.postMessage(JSON.stringify(message));
๋ฉ”์‹œ์ง€ ๋ฐ›์„ ๋•Œ WebView ์ปดํฌ๋„ŒํŠธ์˜ 
onMessage ์†์„ฑ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค
//์•ˆ๋“œ
document.addEventListener('message', getMessageListener);

//ios
window.addEventListener('message', getMessageListener);

 

 

RN์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ

ref๋ฅผ ์‚ฌ์šฉํ•ด์„œ webview์˜ postMessage ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค

๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ผ ๋•Œ๋Š” string๋งŒ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—

JSON.stringify๋กœ ๋ฉ”์‹œ์ง€ ๊ฐ์ฒด๋ฅผ ์ŠคํŠธ๋ง์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค

 

์›น๋ทฐ๋กœ๋ถ€ํ„ฐ 'WEBVIEW_LOADED_MESSAGE_TYPES' ํƒ€์ž…์˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์œผ๋ฉด ํ† ํฐ์„ ์ „์†กํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค

const HomePage = () => {
  const navigation = useNavigation<RootNavigatonProp>();
  const webviewRef = useRef<WebView | null>(null);
  const [token] = useRecoilState(tokenState);

  const postMessage = (message: MessageTypes) => {
    if (!webviewRef.current) return;
    webviewRef.current.postMessage(JSON.stringify(message));
  };

  return (
    <SafeAreaView style={{width: '100%', height: '100%'}}>
      <WebView
        ref={webviewRef}
        source={{uri: WEBVIEW_URI_DEV}}
        style={{flex: 1, width: '100%', height: '100%'}}
        onMessage={ev => {
          const {type, payload} = JSON.parse(
            ev.nativeEvent.data,
          ) as MessageTypes;

          switch (type) {
            case 'WEBVIEW_LOADED_MESSAGE_TYPES':
              if (token) postMessage(onLoginSuccessMessage(token));
              break;
            case 'NAVIGATE_MESSAGE_TYPES':
              navigation.push(payload.stack, payload.params);
              break;
          }
        }}
      />
    </SafeAreaView>
  );
};

export default HomePage;

 

 

 

 

์›น๋ทฐ(Next)์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ

 

1. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ ๋˜๋ฉด ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋๋‹ค๋Š” ๋ฉ”์‹œ์ง€๋ฅผ RN์œผ๋กœ ์ „์†กํ•ฉ๋‹ˆ๋‹ค

2. RN์œผ๋กœ๋ถ€ํ„ฐ 'LOGIN_SUCCESS_MESSAGE_TYPES' ํƒ€์ž…์˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์€ ๊ฒฝ์šฐ payload์— ๋‹ด๊ฒจ์žˆ๋Š” ํ† ํฐ์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค

'use client';

import { tokenState } from '@/store/loginAtom';
import {
  MessageTypes,
  postMessageToWebview,
  webviewLoadedMessage,
} from '@/utils/message';
import { ReactNode, useCallback, useEffect } from 'react';
import { useSetRecoilState } from 'recoil';

const MessageWrapper = ({ children }: { children: ReactNode }) => {
  const setToken = useSetRecoilState(tokenState);

  const getMessageListener = useCallback((event: any) => {
    if (typeof event.data !== 'string') return;
    const eventData = JSON.parse(event.data) as MessageTypes;

    switch (eventData.type) {
      case 'LOGIN_SUCCESS_MESSAGE_TYPES':
        setToken(eventData.payload);
    }
  }, []);

  useEffect(() => {
    document.addEventListener('message', getMessageListener);
    window.addEventListener('message', getMessageListener);
    postMessageToWebview(webviewLoadedMessage());

    return () => {
      document.removeEventListener('message', getMessageListener);
      window.removeEventListener('message', getMessageListener);
    };
  }, []);

  return <div>{children}</div>;
};

export default MessageWrapper;

 

 

 

๊ฐ ๋ฉ”์‹œ์ง€๋“ค์€ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค

type์€ as const๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ทธ ์ž์ฒด๋กœ ํƒ€์ž…์„ ์ธ์ •๋ฐ›๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค

import {TabStackParamList} from '@/routes/TabNavigation';
import {TokenType} from '@/types/auth.types';
import {AllScreenParamsType, MainStackParamList} from '@/types/navigation.type';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';

export const webviewLoadedMessage = () => ({
  type: 'WEBVIEW_LOADED_MESSAGE_TYPES' as const,
  payload: {},
});

export const onBackPressedMessage = () => ({
  type: 'BACK_PRESSED_MESSAGE_TYPES' as const,
  payload: {},
});

export const onExitAppMessage = () => ({
  type: 'EXIT_APP_MESSAEG_TYPES' as const,
  payload: {},
});

export const onLoginSuccessMessage = (token: TokenType) => ({
  type: 'LOGIN_SUCCESS_MESSAGE_TYPES' as const,
  payload: token,
});

export const logoutMessage = () => ({
  type: 'LOGOUT_MESSAGE_TYPES' as const,
  payload: {},
});

export const navigateMessage = (
  stack: keyof MainStackParamList | keyof TabStackParamList,
  params: AllScreenParamsType,
) => ({
  type: 'NAVIGATE_MESSAGE_TYPES' as const,
  payload: {stack, params},
});

export type MessageTypes =
  | ReturnType<typeof webviewLoadedMessage>
  | ReturnType<typeof onBackPressedMessage>
  | ReturnType<typeof onExitAppMessage>
  | ReturnType<typeof onLoginSuccessMessage>
  | ReturnType<typeof logoutMessage>
  | ReturnType<typeof navigateMessage>;

์ฐธ๊ณ 

https://velog.io/@imzzuu/React-Native-%EC%9B%B9%EB%B7%B0-%ED%86%B5%EC%8B%A0%ED%95%98%EA%B8%B0