【问题标题】:Native base Root not works and Element type is invalid error本机基础 Root 不起作用且元素类型无效错误
【发布时间】:2022-01-20 06:53:08
【问题描述】:

我尝试升级一个 React Native 应用程序,其中来自 Native 基础的 Root 组件不受支持并抛出错误为 元素类型无效:应为字符串(对于内置组件)或类/函数(对于复合组件),但得到:未定义。您可能忘记从定义组件的文件中导出组件,或者您可能混淆了默认导入和命名导入。

查看App的渲染方法

App.js

import "react-native-gesture-handler";
import React from 'react';
import {StatusBar, Platform} from 'react-native';
import {Root} from 'native-base';

import {Provider} from 'react-redux';
import {PersistGate} from 'redux-persist/integration/react';

import Routes from './src/routes';

import {store, persistor} from './src/store';


export default class App extends React.Component {
  constructor(props) {
    super(props);
  }
  componentDidMount() {
    console.log('App Called');
  }

  render() {
    return (
      <>
        <Root>
          {Platform.OS === 'ios' && <StatusBar barStyle="dark-content" />}
          <Provider store={store}>
            <PersistGate persistor={persistor}>
              <Routes />
            </PersistGate>
          </Provider>
        </Root>
      </>
    );
  }
}

store/index.js 文件

import AsyncStorage from '@react-native-community/async-storage';
import {createStore, applyMiddleware, compose} from 'redux';
import {persistStore, persistReducer} from 'redux-persist';
import thunk from 'redux-thunk';

import rootReducer from './reducers';

const persistConfig = {
  key: 'root',
  storage: AsyncStorage,
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export const store = createStore(
  persistedReducer,
  composeEnhancers(applyMiddleware(thunk)),
);

export const persistor = persistStore(store);

Package.json

{
  "name": "test",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  },
  "dependencies": {
    "@react-native-community/async-storage": "^1.12.1",
    "@react-native-community/datetimepicker": "^5.0.1",
    "@react-native-community/masked-view": "^0.1.11",
    "@react-native-community/netinfo": "^7.1.6",
    "axios": "^0.24.0",
    "lodash": "^4.17.21",
    "moment": "^2.29.1",
    "native-base": "^3.2.2",
    "obj2fd": "^1.0.6",
    "prop-types": "^15.7.2",
    "react": "17.0.2",
    "react-native": "0.66.4",
    "react-native-document-picker": "^7.1.2",
    "react-native-dropdown-picker": "^5.2.3",
    "react-native-elements": "^3.4.2",
    "react-native-fix-image": "^2.1.0",
    "react-native-fs": "^2.18.0",
    "react-native-gesture-handler": "^2.1.0",
    "react-native-image-picker": "^4.6.0",
    "react-native-image-resizer": "^1.4.5",
    "react-native-image-zoom-viewer": "^3.0.1",
    "react-native-keyboard-aware-scrollview": "^2.1.0",
    "react-native-modal": "^13.0.0",
    "react-native-modal-datetime-picker": "^13.0.0",
    "react-native-reanimated": "2.2.4",
    "react-native-restart": "^0.0.22",
    "react-native-safe-area-context": "^3.3.2",
    "react-native-screens": "^3.10.1",
    "react-native-svg": "^12.1.1",
    "react-native-vector-icons": "^9.0.0",
    "react-native-view-shot": "^3.1.2",
    "react-navigation": "^4.4.4",
    "react-navigation-stack": "^2.10.4",
    "react-navigation-tabs": "^2.11.1",
    "react-redux": "^7.2.6",
    "redux": "^4.1.2",
    "redux-devtools-extension": "^2.13.9",
    "redux-persist": "^6.0.0",
    "redux-promise": "^0.6.0",
    "redux-thunk": "^2.4.1",
    "rn-fetch-blob": "^0.12.0",
    "simple-react-validator": "^1.6.1"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@babel/runtime": "^7.12.5",
    "@react-native-community/eslint-config": "^2.0.0",
    "babel-jest": "^26.6.3",
    "eslint": "7.14.0",
    "jest": "^26.6.3",
    "metro-react-native-babel-preset": "^0.66.2",
    "react-devtools": "^4.21.0",
    "react-test-renderer": "17.0.2"
  },
  "jest": {
    "preset": "react-native"
  }
}

还有文件routes.js

import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';

import * as screens from '../screens';
import AppNavigation from '../screens/app/stack';


const InitNavigator = createStackNavigator(
  {
    Splash: {
      screen: screens.Splash,
      navigationOptions: {
        headerShown: false,
      },
    },
    SignIn: {
      screen: screens.SignIn,
      navigationOptions: {
        headerShown: false,
      },
    },
    ForgotPassword: {
      screen: screens.ForgotPassword,
      navigationOptions: {
        headerShown: false,
      },
    },
    OTPVerification: {
      screen: screens.OTPVerification,
      navigationOptions: {
        headerShown: false,
      },
    },
    AppNavigation: {
      screen: AppNavigation,
      navigationOptions: {
        headerShown: false,
      },
    },
  },
  {
    navigationOptions: {
      headerShown: false,
    },
    initialRouteName: 'Splash',
  },
);

export default createAppContainer(InitNavigator);

当我刚刚删除 App.js 中的 Root 时,只加载了启动画面。剩余的屏幕未加载并引发相同的元素类型错误。

screens/index.js

export {default as Splash} from '../screens/splash';
export * from '../screens/auth';
export * from '../screens/app';

下一个auth/index.js

export {default as SignIn} from './signIn';
export {default as ForgotPassword} from './forgotPassword';
export {default as OTPVerification} from './otpVerification';

SignIn 页面

import React, {useState} from 'react';
import {
  View,
  Text,
  TouchableOpacity,
  StyleSheet,
  Dimensions,
} from 'react-native';
import PropsType from 'prop-types';
import {connect} from 'react-redux';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scrollview';
import SimpleReactValidator from 'simple-react-validator';

import {Img} from '../../../common';
import Loader from '../../../common/Loader/Loader';
import styles from '../../../globalStyle';
import AxiosInstance from '../../../helper/axios.interceptor';
import * as theme from '../../../theme';
import * as globalHelper from '../../../helper/globalHelper';

import {setAuth} from '../../../store/auth/auth.action';
import LoginForm from './components/LoginForm';

const {height} = Dimensions.get('screen');

const propsType = {
  authAction: PropsType.func,
};

let request = {type: 'mobile'};
const validator = new SimpleReactValidator();

const SignIn = ({navigation, authAction}) => {
  const [errors, setErrors] = useState({});

  const [state, setState] = useState({loader: false}),
    updateState = (key, value) => {
      setState((preState) => ({
        ...preState,
        [key]: value,
      }));
    },
    openLoader = (val) => {
      updateState('loader', val);
    };
  const submit = async () => {
    try {
      openLoader(true);
      let body = {
        type: 'mobile',
        userName: request.userName,
        password: request.password,
      };
      console.log("body",body)
      const response = await AxiosInstance.post('auth/login', body);
      console.log('loginresponse...', response);
      if (response.status) {
        await globalHelper.setAsyncStore('user', response);
        await globalHelper.setAsyncStore('userpermission', response.data.permissionJson);
        authAction(response);
        navigation.replace('AppNavigation');
      }
      openLoader(false);
    } catch (err) {
      openLoader(false);
      console.log("login error",err);
    }
  };
  //
  const ForgotPassword = () => (
    <TouchableOpacity
      onPress={() => {
        validator.hideMessages();
        setErrors('');
        navigation.push('ForgotPassword');
      }}>
      <Text style={[localStyle.forgotText]}>Forgot Password?</Text>
    </TouchableOpacity>
  );

  return (
    <>
      <KeyboardAwareScrollView>
        <View style={[styles.flexCenter, {height}]}>
          <Img
            src={require('../../../assets/logo/logoNew.png')}
            style={{width: 237,height:250,marginBottom:-20}}
            resizeMode="contain"
          />
          <View style={localStyle.authButton}>
            <LoginForm
              validator={validator}
              onTextChanging={(data) => {
                request = {...request, ...data};
              }}
              onSubmit={() => {
                submit();
              }}
              errors={errors}
              setErrors={setErrors}
            />
          </View>
          <View style={[styles.flexCenter]}>
            <ForgotPassword />
          </View>
        </View>
      </KeyboardAwareScrollView>
      {state.loader && <Loader />}
    </>
  );
};
const {color} = theme;

const localStyle = StyleSheet.create({
  authButton: {
    width: '80%',
    borderRadius: 5,
  },
  forgotText: {
    marginTop: 20,
    color: color.hashTextColor,
  },
});

SignIn.propsType = propsType;

const mapDispatchToProps = {
  authAction: setAuth,
};

export default connect(null, mapDispatchToProps)(SignIn);

最后是Splash页面

import React, {useEffect} from 'react';
import {View, PermissionsAndroid} from 'react-native';
import {Toast} from 'native-base';
import {connect} from 'react-redux';
import PropsType from 'prop-types';
import NetInfo from '@react-native-community/netinfo';
import RNRestart from 'react-native-restart';

import {Img} from '../../common';

import * as globalHelper from '../../helper/globalHelper';
import styles from '../../globalStyle';

import {setAuth} from '../../store/auth/auth.action';

const propsType = {
  authAction: PropsType.func,
};
const defaultProps = {
  authAction: () => {},
};
const Splash = ({navigation, authAction}) => {
  const getNetworkIssues = () => {
    NetInfo.addEventListener(async nState => {
      if (!nState.isConnected) {
        await Toast.show({
          text: 'Please connect Network',
          // duration: 100000,
          buttonText: 'Reload',
          onClose: reason => {
            if (reason === 'user' && nState.isConnected) {
              RNRestart.Restart();
            }
          },
        });
      }
    });
  };

  const goInit = async () => {
    try {
      getNetworkIssues();
      await PermissionsAndroid.requestMultiple([
        PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
        PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
      ]);
      const user = await globalHelper.getAsyncStore('user');
      if (user) {
        authAction(JSON.parse(user));
        navigation.replace('AppNavigation');
      } else {
        setTimeout(() => {
          navigation.navigate('SignIn');
        }, 1500);
      }
    } catch (err) {
      console.log(err);
    }
  };

  useEffect(() => {
    goInit();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return (
    <View style={[styles.flexCenter, {height: '100%'}]}>
      <Img
        src={require('../../assets/logo/logoNew.png')}
        style={{wdith: 237, height: 250}}
      />
    </View>
  );
};

Splash.propsType = propsType;
Splash.defaultProps = defaultProps;

const mapDispatchtoProps = {
  authAction: setAuth,
};

export default connect(null, mapDispatchtoProps)(Splash);

我也尝试了 withNavigation 添加了来自react-navigationconnect。它没有奏效。并且 export default 关键字被正确使用,但我仍然面临错误。无法找到任何根本原因。提前感谢那些帮助解决这个问题的人。

【问题讨论】:

    标签: react-native react-navigation native-base


    【解决方案1】:

    Nativebase 3.2.2 没有根组件

    参考setup-provider for nativebase v3

    import React from 'react';
    // 1. import `NativeBaseProvider` component
    import { NativeBaseProvider, Text, Box } from 'native-base';
    
    export default function App() {
      // 2. Use at the root of your app
      return (
        <NativeBaseProvider>
          <Box flex={1} bg="#fff" alignItems="center" justifyContent="center">
            <Text>Open up App.js to start working on your app!</Text>
          </Box>
        </NativeBaseProvider>
      );
    }
    

    【讨论】:

      猜你喜欢
      • 2020-04-02
      • 2021-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多