Nx를 사용하여 React Web과 React Native Mobile 간에 코드 공유
저는 주로 인터넷 개발자이기 때문에 먼저 인터넷 응용 프로그램부터 시작하겠습니다. https://xiongemi.github.io/studio-ghibli-search-engine.그것은 지브리 스튜디오의 영화와 캐릭터 검색엔진이다.
Github 재구매: https://github.com/xiongemi/studio-ghibli-search-engine
Github 페이지: https://xiongemi.github.io/studio-ghibli-search-engine
이제 이 프로그램의 모바일 버전을 만듭니다.
기술 스택
nx dep-graph
을 실행하는 경우 종속성 다이어그램은 다음과 같습니다.리액션 네이티브 설정
시작하려면 Nx 작업공간에 React 네이티브 지원을 추가해야 합니다.
# npm
npm install @nrwl/react-native --save-dev
# yarn
yarn add @nrwl/react-native --dev
그런 다음 다음 다음 프로그램을 실행하여 새로운 React 기본 응용 프로그램을 생성할 수 있습니다.npx nx generate @nrwl/react-native:app studio-ghibli-search-engine-mobile
Note, if you’re using VSCode you might want to try Nx Console for a more visual experience of running such commands.
위 명령을 실행하면 현재
apps
디렉토리에 studio-ghibli-search-engine-mobile
과 studio-ghibli-search-engine-mobile-e2e
두 개의 새 폴더가 있어야 합니다.현재
nx dep-graph
을 다시 실행하면 의존 관계도는 다음과 같습니다.studio-ghibli-search-engine-mobile
과 studio-ghibli-search-engine-web
사이에 공유 코드가 없습니다.그러나, 우리의 목표는 웹 버전을 위한 새로운 React 본체 버전의 응용 프로그램에서 웹 버전을 위한 일부 기능을 다시 사용하는 것이다.공유할 수 없는 코드
비록 우리의 목표는 React 웹 응용 프로그램과 React 원본 응용 프로그램 사이에서 가능한 한 많이 공유하는 것이지만, 일부 부분은 근본적으로 공유할 수 없다.
사용자 인터페이스
모바일 애플리케이션의 모든 UI 구성 요소를 다시 작성해야 합니다.React Native는 Cordova 또는 Ionic과 달리 네트워크 뷰가 아닙니다.작성한 JavaScript는 로컬 요소를 이동하는 것으로 해석되고 변환됩니다.따라서 React 웹 응용 프로그램에 작성된 UI HTML 요소를 간단하게 재사용할 수 없습니다.
다음은 React 웹 응용 프로그램에 사용할 라이브러리의 빠른 목록과 우리가 사용할 수 있는 해당 React 본체 대응 라이브러리입니다.
경로
# npm
npm install @react-navigation/native @react-navigation/native-stack react-native-paper react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view --save
# yarn
yarn add @react-navigation/native @react-navigation/native-stack react-native-paper react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
보관부
React 웹 응용 프로그램에 대해 우리는 redux-persist을 사용합니다. 이것은 Redux 상점을 localstorage에 저장합니다.그러나 React Native는
localstorage
을 지원하지 않습니다.웹의 경우 redux persist에서 persistStore로 전달되는 변수
persistConfig
은 다음과 같습니다.import storage from 'redux-persist/lib/storage';
const persistConfig = {
key: 'root',
storage: storage,
whitelist: ['search', 'films', 'people'],
transforms: [transformEntityStateToPersist],
};
하지만 모바일 장치의 경우 @react-native-async-storage/async-storage 라이브러리를 설치해야 합니다.# npm
npm install @react-native-async-storage/async-storage --save-dev
# yarn
yarn add @react-native-async-storage/async-storage --dev
따라서 Redux persist에서 persistStore로 전달되는 persistConfig
은 다음과 같습니다.import AsyncStorage from '@react-native-async-storage/async-storage';
const persistConfig = {
key: 'root',
storage: AsyncStorage,
whitelist: ['search', 'films', 'people'],
transforms: [transformEntityStateToPersist],
};
역사.
React 웹 응용 프로그램에서, 우리는 connected-react-router을 사용하여 공유기 상태를 Redux 상점에 넣었다.그러나 React Native는 History API (windows.history)을 지원하지 않습니다.대안으로
createMemoryHistory
을 사용할 수 있습니다.웹 응용 프로그램의 사용 내역은 다음과 같습니다.
import { createHashHistory, History } from 'history';
const history: History = createHashHistory();
모바일 애플리케이션의 경우 사용 내역은 다음과 같습니다.import { createMemoryHistory, History } from 'history';
const history: History = createMemoryHistory();
코드를 다시 사용하기 위해서 우리는 connected-react-router을 사용하여 루트 축소기의 생성을 약간 재구성할 수 있다. 그러면 history
의 대상을 매개 변수로 할 수 있다.import { combineReducers } from '@reduxjs/toolkit';
import { connectRouter } from 'connected-react-router';
import { History } from 'history';
import { filmsSlice } from '../films/films.slice';
import { peopleSlice } from '../people/people.slice';
import { searchSlice } from '../search/search.slice';
import { RootState } from './root-state.interface';
export const createRootReducer = (history: History) =>
combineReducers<RootState>({
films: filmsSlice.reducer,
router: connectRouter(history) as any,
search: searchSlice.reducer,
people: peopleSlice.reducer,
});
질의 매개변수
웹에서 개발할 때 상태나 정보를 전달하는 가장 간단한 방법은 보통 URL을 이용하여 파라미터를 조회하는 것이다.우리의 검색 프로그램 예시에서 우리는
?search=searchText
과 비슷한 것을 간단하게 사용할 수 있다.우리는 react-router-dom을 사용하여 새로운 역사 항목을 전달할 수 있다.
import { useHistory } from 'react-router-dom';
const history = useHistory();
const submitSearchForm = (text: string) => {
history.push(`${AppRoutes.results}?search=${text}`);
};
현재 질의 매개변수 search
을 읽고 분석하려면 다음과 같이 하십시오.import { useLocation } from 'react-router-dom';
const params = new URLSearchParams(useLocation().search);
const searchParam = params.get('search');
URL은 모바일 애플리케이션에 표시되지 않지만 매개 변수를 전달할 수 있습니다.다른 패키지인 @react-navigation/native
을 사용해야 합니다.import { useNavigation } from '@react-navigation/native';
const navigation = useNavigation();
const submitSearchForm = () => {
navigation.navigate(AppRoutes.results, { search: text });
};
매개변수를 읽고 분석하려면 다음과 같이 하십시오.import { RouteProp, useRoute } from '@react-navigation/native';
const route = useRoute<RouteProp<{ params: { search: string } }>>();
const searchParam = route.params?.search;
typescript를 사용하여react 내비게이션의 유형 검사를 진행하려면, 루트 이름을 루트에 비추는 파라미터인 RootStackParamList
형식을 만들어야 합니다.export type RootStackParamList = {
[AppRoutes.search]: undefined;
[AppRoutes.results]: { search: string };
};
또한 루트 탐색기의 글로벌 유형을 지정해야 합니다.declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace ReactNavigation {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface RootParamList extends RootStackParamList {}
}
}
So we create the stack navigator, we need to pass the above `RootStackParamList` type:
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator<RootStackParamList\>();
환경 변수
Nx는 handling environment variables의 다양한 옵션을 제공합니다.작업공간 루트 디렉토리에는 간단한
.env
파일이 있습니다.NX_REQUEST_BASE_URL=://ghibliapi.herokuapp.com
이것은 우리의React 웹 구축에 매우 효과적이지만, 우리의React 본체 응용 프로그램에는 그렇지 않다.React Native와 React 애플리케이션이 서로 다른 Javascript 바인딩기를 사용하기 때문입니다.React Native는 Metro을, React는 Webpack을 사용합니다.그래서 우리가 process.env.NX_REQUEST_BASE_URL
을 방문하려고 시도했을 때 우리는 undefined
을 얻었다.이 문제를 해결하기 위해 react-native-config 라이브러리를 사용할 수 있습니다.
# npm
npm install react-native-config --save-dev
# yarn
yarn add react-native-config --dev
다음은 react-native-config을 설정하는 방법의 예: https://github.com/luggit/react-native-config#setup.이후에 우리는 간단한 실용 함수를 사용하여 응용 프로그램의 환경 변수를 검색할 수 있다.
import Config from 'react-native-config';
export function getEnv(envName: string) {
return process.env[envName] || Config[envName];
}
환경 변수 NX_REQUEST_BASE_URL
에 접근하려면 위의 함수: getEnv(‘NX_REQUEST_BASE_URL’)
을 사용하십시오.HTTP를 사용하여 가져오기
인터넷상에서, 당신은 fetch API에 의존하여 네트워크 요청을 할 가능성이 매우 높다.그러나 iOS에서 당신은
TypeError: Network request failed
의 오류를 얻게 될 것입니다.React Native는 기본적으로 HTTP 요청을 허용하지 않습니다. https://stackoverflow.com/questions/38418998/react-native-fetch-network-request-failed.
이 문제를 해결하려면 iOS의 경우
apps/studio-ghibli-search-engine-mobile/ios/StudioGhibliSearchEngineApp/Info.plist
을 열고 요청 URL을 NSExceptionDomains
의 NSAppTransportSecurity
에 추가합니다.<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
<key>ghibliapi.herokuapp.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
마찬가지로 Android의 경우 apps/studio-ghibli-search-engine-mobile/android/app/src/main/res/xml/network_security_config.xml
을 열고 요청 URL을 이 구성 파일에 추가합니다.<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.0.2.2</domain>
<domain includeSubdomains="true">localhost</domain>
<domain includeSubdomains="true">herokuapp.com</domain>
</domain-config>
</network-security-config>
그러면 네트워크 오류가 제거됩니다.React 네이티브 애플리케이션의 경우 많은 사용자 정의가 필요할 것 같습니다.그러나 대부분의 비 UI 코드는 재사용할 수 있습니다.
공유 가능한 코드
UI가 아닌 모든 비즈니스 논리 코드를 공유할 수 있습니다.이 예에서 나는 monorepo에서 3개의 라이브러리를 얻었는데 모두 공유할 수 있다.
nx generate @nrwl/react:lib store
같은 명령을 사용했지만, 나는react 원본 모바일 응용 프로그램에서 그것들을 직접 사용할 수 있다.예를 들어, 필름의 세부내용을 표시하고 필름 id를 매개 변수로 전달할 필름 페이지를 만들어야 합니다.
스토어 라이브러리에서 직접 가져오기:
import {
filmsActions,
filmsSelectors,
RootState,
} from '@studio-ghibli-search-engine/store';
영화의 구성 부분은 다음과 같다.참고: @studio-ghibli-search-engine/models
, @studio-ghibli-search-engine/services
및 @studio-ghibli-search-engine/store
에서 직접 가져올 수 있습니다
현재 내가 nx dep-graph
을 실행할 때 의존 관계도를 나타낸다. 아래와 같이 이 세 라이브러리는 웹과 모바일 기기 사이에서 공유된다.
이 예시 항목에 대해 모바일 프로그램을 만들기 위해 UI 전체를 다시 쓰는 데 시간이 좀 걸렸습니다.하지만 위의 라이브러리를 너무 많이 변경할 필요는 없습니다
결론
본고에서 우리는 최종적으로 Nx을 사용하여 같은 메모리 라이브러리에서 React 기반의 웹 응용 프로그램과 상응하는 React 본체 응용 프로그램을 구축하였다
Nx의 구조는 관심점의 분리를 추진하고 사물을 apps
(기술에 특정)과 libs
(기술에 특정하거나 기술에 독립)으로 나눈다.이것은 우리로 하여금 기술과 독립된 라이브러리에서 우리의 일반적인 업무 논리를 쉽게 가지게 하고, 이 라이브러리(Nx의 설정 덕분)는 우리의React 웹과 React 원본 모바일 응용 프로그램에 쉽게 연결할 수 있게 한다.p>
UI의 구체적인 차이를 고려해야 하지만 하나는 웹 기술 창고이고 다른 하나는 로컬 응용 프로그램이지만, 우리는 여전히 응용 프로그램에서 기술과 무관한 대량의 업무 논리를 공유할 수 있다.이것은 결국 서로 다른 플랫폼 간의 유지보수와 기능의 피어에 도움이 된다
(본문 코드를 포함하는 저장소 링크가 맨 위에 있음 주의)
Reference
이 문제에 관하여(Nx를 사용하여 React Web과 React Native Mobile 간에 코드 공유), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/nx/share-code-between-react-web-react-native-mobile-with-nx-12eb텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)