我正在尝试自学React Native + Firebase。我遵循了https://levelup.gitconnected.com/how-to-use-the-react-context-api-to-build-react-native-expo-and-firebase-apps-adda840e52b0中列出的教程。本教程中的示例是当用户登录时,App导航器转到主页,该页面仅包含一个注册按钮。
我想创建一个BottomTabNavigator,其中还包括一个“设置”组件和一个虚拟屏幕。虚拟屏幕出现并且可以工作,但是当我单击“设置”选项卡时,我不断收到以下错误:
“未捕获的不变违反:元素类型无效:应为 字符串(对于内置组件)或类/函数(对于复合 组件),但未定义。您可能忘记了导出 定义文件中的组件。”
这是我的代码:
index.js
const SwitchNavigator = createSwitchNavigator(
{
Initial: Initial,
Auth: AuthNavigation,
App: AppNavigation
},
{
initialRouteName: 'Initial'
}
)
const AppContainer = createAppContainer(SwitchNavigator)
export default AppContainer
AppNavigation.js
import { createStackNavigator } from 'react-navigation-stack'
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import Home from '../screens/Home';
import DummyScreen2 from '../screens/DummyScreen2'
import SettingsHook from '../screens/SettingsHook'
const AppNavigation = createAppContainer(
createBottomTabNavigator({
Home: {
screen: Home,
navigationOptions: {
tabBarLabel: 'Home',
},
},
SettingsHook: {
screen: SettingsHook,
navigationOptions: {
tabBarLabel: 'SettingsHook',
},
},
DummyScreen2: {
screen: DummyScreen2,
navigationOptions: {
tabBarLabel: 'DummyScreen2',
},
},
})
);
AuthNavigation.js
const AuthNavigation = createStackNavigator(
{
Login: { screen: Login },
Signup: { screen: Signup },
ForgotPassword: { screen: ForgotPassword },
},
{
initialRouteName: 'Login',
headerMode: 'none'
}
)
export default AuthNavigation
SettingsHook.js
const SettingsHook = () => {
const [modalVisible, setmodalVisible] = useState(false)
const [budget, setBudget] = useState(850)
const [monthly, setMonthly] = useState(1700)
const [notifications, setNotifications] = useState(true)
const [newsletter, setNewsletter] = useState(false)
const [editing, setEditing] = useState(null)
const [profile, setProfile] = useState({})
const [firstName, setFirstName] = useState('')
const [lastName, setLastName] = useState('')
const [email, setEmail] = useState('')
const [cardNumber, setCardNumber] = useState(0)
const [last3Digits, setLast3Digits] = useState(0)
useEffect(()=>{
setProfile(profile)
})
const toggleEdit = (name) => {
// const { editing } = this.state;
// this.setState({ editing: !editing ? name : null });
setEditing(!editing ? name : null )
}
const renderEdit =(name) => {
// const { profile, editing } = this.state;
if (editing === name) {
return (
<TextInput
defaultValue={profile[name]}
onChangeText={text => handleEdit([name], text)}
/>
)
}
return <Text bold>{profile[name]}</Text>
}
const handleEdit = (name, text) => {
profile[name] = text;
// this.setState({ profile });
setProfile(profile)
}
const setModalVisible = (visible) => {
// this.setState({ modalVisible: visible });
setmodalVisible(visible)
}
const handleSubmit=()=> {
// do the things
Alert.alert('Updated payment method successfully!')
// this.setState({ modalVisible: false })
setmodalVisible(false)
}
const addPaymentInfo= () => {
return (
<Modal animationType="slide" visible={modalVisible} onRequestClose={() => setmodalVisible(false)}>
<Text> Payment Information </Text>
<View>
<TextInput
placeholder="First Name"
onChangeText={text => setFirstName(text)}
/>
<TextInput
placeholder="Last Name"
// onChangeText={text => this.setState({lastName: text })}
onChangeText={text => setLastName(text)}
/>
<TextInput
placeholder="Email"
keyboardType='email-address'
onChangeText={text => setEmail(text)}
/>
<TextInput
secureTextEntry={true}
keyboardType='number-pad'
placeholder="Credit Card Number"
onChangeText={text => setCardNumber(text)}
/>
<TextInput
secureTextEntry={true}
keyboardType='numeric'
placeholder="Last 3 digits:"
onChangeText={text => setLast3Digits(text)}
/>
</View>
{/* <Button gradient onPress={() => setmodalVisible(false)}> */}
<Button gradient onPress={handleSubmit}>
<Text center white>Submit</Text>
</Button>
</Modal>
)
}
// const { profile, editing } = this.props;
return (
<Block>
<Block flex={false} row center space="between" style={styles.header}>
<Text h1 bold>Settings Hook</Text>
<Button>
<Image source={profile.avatar} style={styles.avatar} />
</Button>
</Block>
<ScrollView showsVerticalScrollIndicator={false}>
<Block style={styles.inputs}>
<Block row space="between" margin={[10, 0]} style={styles.inputRow}>
<Block>
<Text gray2 style={{ marginBottom: 10 }}>Username</Text>
{renderEdit('username')}
</Block>
<Text medium secondary onPress={() => toggleEdit('username')}>
{editing === 'username' ? 'Save' : 'Edit'}
</Text>
</Block>
<Block row space="between" margin={[10, 0]} style={styles.inputRow}>
<Block>
<Text gray2 style={{ marginBottom: 10 }}>Location</Text>
{renderEdit('location')}
</Block>
<Text medium secondary onPress={() => toggleEdit('location')}>
{editing === 'location' ? 'Save' : 'Edit'}
</Text>
</Block>
<Block row space="between" margin={[10, 0]} style={styles.inputRow}>
<Block>
<Text gray2 style={{ marginBottom: 10 }}>E-mail</Text>
<Text bold>{profile.email}</Text>
</Block>
</Block>
</Block>
<Button onPress={() => setmodalVisible(true)}>
<Text center caption gray>Update Payment Information</Text>
</Button>
{addPaymentInfo()}
<Divider margin={[theme.sizes.base, theme.sizes.base * 2]} />
<Block style={styles.sliders}>
<Block>
<Text gray2>Budget</Text>
<Slider
minimumValue={0}
maximumValue={1000}
style={{ height: 19 }}
thumbStyle={styles.thumb}
trackStyle={{ height: 6, borderRadius: 6 }}
minimumTrackTintColor={theme.colors.secondary}
maximumTrackTintColor="rgba(157, 163, 180, 0.10)"
value={budget}
onValueChange={value => setBudget(value)}
/>
<Text caption gray2 right>$1,000</Text>
</Block>
</Block>
<Divider />
<Block style={styles.toggles}>
<Block row center space="between">
<Text gray2>Notifications</Text>
<Switch
value={notifications}
onValueChange={value => setNotifications(value)}
/>
</Block>
<Block row center space="between">
<Text gray2>Newsletter</Text>
<Switch
value={newsletter}
onValueChange={value => setNewsletter(value)}
/>
</Block>
</Block>
</ScrollView>
</Block>
);
}
SettingsHook.defaultProps = {
profile: mocks.profile,
}
export default SettingsHook
DummyScreen2.js
export default class DummyScreen2 extends Component {
render() {
return (
<View style={styles.container}>
<Block>
<Text>Dummy Screen 2</Text>
</Block>
<Button
title='Signout'
// onPress={this.handleSignout}
titleStyle={{
color: '#F57C00'
}}
type='clear'
/>
</View >
)
}
}