react-navigation 跟 原生的 navigator 可以同时存在吗

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了react-navigation 跟 原生的 navigator 可以同时存在吗相关的知识,希望对你有一定的参考价值。

参考技术A 1.下载和安装在项目根目录执行:npminstall--savereact-navigation2.在js文件中引入我们需要的组件importStackNavigatorfrom'react-navigation';3.开始使用importHomefrom'./Home';importMainsfrom'./Second';[html]viewplaincopyconstApp=StackNavigator(Home:screen:Home,Chat:screen:Second,Two:screen:Mains);

无法让 Jest expo 应用程序与 react-navigation 一起使用

【中文标题】无法让 Jest expo 应用程序与 react-navigation 一起使用【英文标题】:Can't get Jest expo app to work with react-navigation 【发布时间】:2020-03-27 10:00:30 【问题描述】:

我正在尝试使用 Jest、Expo、React Navigation 进行快照测试,而我的整个应用程序仅使用钩子。我希望最终将这些变成 e2e 测试,在其中 Jest 单击并快照测试所有内容,但我什至无法获得反应导航来渲染。我在博览会加载器之后的快照总是显示“null”。我遵循expo init 附带的选项卡启动器中的基本示例,但它概述如何设置模拟的方式根本不适用于我的应用程序。我尝试了各种方法,但没有任何效果。

App.tsx

import  Ionicons  from '@expo/vector-icons';
import  AppLoading  from 'expo';
import  Asset  from 'expo-asset';
import * as Font from 'expo-font';
import React,  useState  from 'react';
import  YellowBox  from 'react-native';
import  Provider as PaperProvider  from 'react-native-paper';
import  useScreens  from 'react-native-screens';
import  Provider as RxProvider  from 'reactive-react-redux';
import  applyMiddleware, compose, createStore  from 'redux';
import thunk from 'redux-thunk';
import SnackBar from './components/UI/Snackbar';
import  socketMiddleware  from './lib/socketMiddleware';
import SwitchNavigator from './navigation/AppNavigator';
import rootReducer from './reducers/rootReducer';
import  theme  from './Theme';

const middleware = [thunk, socketMiddleware()];
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export const store = createStore<iAppState, any, any, any>(
  rootReducer,
  composeEnhancers(applyMiddleware(...middleware))
);

// Must be called prior to navigation stack rendering
useScreens();

YellowBox.ignoreWarnings(['Require cycle:']);

const App = (props) => 
  const [isLoadingComplete, setLoadingComplete] = useState(false);

  if (!isLoadingComplete && !props.skipLoadingScreen) 
    return (
      <AppLoading
        startAsync=loadResourcesAsync
        onError=handleLoadingError
        onFinish=() => handleFinishLoading(setLoadingComplete)
      />
    );
   else 
    return (
      <RxProvider store=store>
        <PaperProvider theme=theme>
          <SwitchNavigator />
          <SnackBar />
        </PaperProvider>
      </RxProvider>
    );
  
;

const loadResourcesAsync = async () => 
  await Promise.all([
    Asset.loadAsync([
      //nothing
    ]),
    Font.loadAsync(
      ...Ionicons.font,
      TitilliumText250: require('./assets/fonts/TitilliumText22L-250wt.otf'),
      TitilliumText800: require('./assets/fonts/TitilliumText22L-800wt.otf')
    )
  ]);
;

const handleLoadingError = (error: Error) => 
  console.warn(error);
;

const handleFinishLoading = (setLoadingComplete) => 
  setLoadingComplete(true);
;

export default App;

App.test.tsx:

import React from 'react';
import  Provider as PaperProvider  from 'react-native-paper';
import NavigationTestUtils from 'react-navigation/NavigationTestUtils';
import renderer from 'react-test-renderer';
import App from './App';
import  theme  from './Theme';

jest.mock('expo', () => (
  AppLoading: 'AppLoading'
));
jest.mock('react-native-screens');
jest.mock('react-native-paper');
jest.mock('redux');
jest.mock('reactive-react-redux');
jest.mock('./navigation/AppNavigator', () => 'SwitchNavigator');

describe('App', () => 
  jest.useFakeTimers();

  beforeEach(() => 
    NavigationTestUtils.resetInternalState();
  );

  // success
  it(`renders the loading screen`, () => 
    const tree = renderer.create(<App />).toJSON();
    expect(tree).toMatchSnapshot();
  );

  // this snapshot is always null
  it(`renders the root without loading screen`, () => 
    const tree = renderer
      .create(
        <PaperProvider theme=theme>
          <App skipLoadingScreen></App>
        </PaperProvider>
      )
      .toJSON();
    expect(tree).toMatchSnapshot();
  );
);

/navigation/AppNavigator.tsx:

import  createAppContainer, createSwitchNavigator  from 'react-navigation';
import LoginStack from './LoginStack';
import TabStack from './TabStack';

/** The most root navigator which allocates to the others. */
const SwitchNavigator = createAppContainer(
  createSwitchNavigator(
    
      LoginStack: LoginStack,
      TabStack: TabStack
    ,
    
      initialRouteName: 'LoginStack'
    
  )
);

export default SwitchNavigator;

【问题讨论】:

【参考方案1】:

我遇到了类似的问题,并通过以下方式找到了解决方法:https://github.com/expo/expo/issues/7155#issuecomment-592681861

似乎 act() 对我来说神奇地阻止它返回 null(不确定如何)

更新您的测试以像这样使用它:

import  act, create  from 'react-test-renderer';

it('renders the root without loading screen', () => 
    let tree;

    act(() => 
      tree = create(
        <PaperProvider theme=theme>
          <App skipLoadingScreen></App>
        </PaperProvider>
      );
    );

    expect(tree.toJSON()).toMatchSnapshot();
  );

注意:当我更改使用“react-test-renderer”导入的方式时,我的测试无法找到 act() 作为函数,一个简单的 npm 包重新安装解决了这个问题!

【讨论】:

以上是关于react-navigation 跟 原生的 navigator 可以同时存在吗的主要内容,如果未能解决你的问题,请参考以下文章

退出抽屉内的子堆栈导航器时,如何使用 react-navigation 进入 initialRoute?

无法让 Jest expo 应用程序与 react-navigation 一起使用

initialProps被React-Navigation的navigation属性覆盖解决方案

测试套件无法使用 @react-navigation/stack 运行

反应原生,侧边菜单没有出现

从反应原生底部选项卡导航器的标题导航