【发布时间】: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-navigation 的connect。它没有奏效。并且 export default 关键字被正确使用,但我仍然面临错误。无法找到任何根本原因。提前感谢那些帮助解决这个问题的人。
【问题讨论】:
标签: react-native react-navigation native-base