Component for route must be a React component - react-native

I'm trying to make an app with React native and Expo. Im trying to make a navigation from my Profiel.js to ChoosePhoto.js. When im opening the app on my android emulator i'm getting the error "The component for route ProfielS must be a React component.
the navigator
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import ProfielScreen from '../screens/Profiel';
import PhotoScreen from '../screens/ChoosePhoto';
const ProfielNavigator = createStackNavigator ({
ProfielS: ProfielScreen,
PhotoS: PhotoScreen
});
export default createAppContainer(ProfielNavigator);
my app.js
import React from 'react';
import { Text, View, StyleSheet, } from 'react-native';
import ProfielNavigator from './navigation/ProfielNavigator';
export default function App() {
return (
<ProfielNavigator />
);
};
my profiel.js
import React from 'react';
import { Text, View, StyleSheet, Button, Fragement } from 'react-native';
export class GebruikerScherm extends React.Component {
componentWillMount() {
this.getData();
}
constructor() {
super();
this.state = {
gebruikerId: 2,
currentPerson: {},
}
}
getData = () => {
return fetch('(my ip adress)/gebruiker/id?gebruikerId=' + this.state.gebruikerId, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({ currentPerson: responseJson });
console.log(this.state.currentPerson);
})
.catch((error) => {
console.error(error);
});
}
render() {
return(
<View style={styles.container}>
<Text> Gebruiker: {this.state.currentPerson.gebruikerID} </Text>
<Text> Gebruiker: {this.state.currentPerson.gebruikerNaam} </Text>
<Text> Gebruiker: {this.state.currentPerson.biografie} </Text>
</View>
);
};
};
export const ProfielScreen = props =>{
return(
<View style={styles.container}>
<Button title="Profielfoto" onPress={() => {
props.navigation.navigate({
routeName: 'PhotoS'
});
}} />
</View>
);
};
const styles = StyleSheet.create({
container: {
marginTop: 200,
width: '100%',
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
}
});
Choosephoto.js
import React from 'react';
import { Text, View, StyleSheet, } from 'react-native';
const ChoosePhotoScreen = props =>{
return(
<View style={styles.container}>
<Button title="Profielfoto" onPress={() => {
props.navigation.navigate({
routeName: 'PhotoS'
});
}} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default ChoosePhotoScreen;
I expect my profiel.js page with a button. With the onpress action i want to go from profiel.js to choosephoto.js but the page wont even load.

You are wrong in the way you bring in objects.
The object you are trying to use is export only. Not export default
your profiel.js
export const ProfielScreen = props =>{
return(
<View style={styles.container}>
<Button title="Profielfoto" onPress={() => {
props.navigation.navigate({
routeName: 'PhotoS'
});
}} />
</View>
);
};
your Choosephoto.js
...
export default ChoosePhotoScreen;
Usage
import { ProfielScreen } from '../screens/Profiel';
import ChoosePhotoScreen as PhotoScreen from '../screens/ChoosePhoto';
...
const ProfielNavigator = createStackNavigator ({
ProfielS: ProfielScreen,
PhotoS: PhotoScreen
});
Example
import React from 'react'
This essentially says "find the default export from the react module and import that as a constant that I want to call React."
import { React } from 'react'
This says "find the export from the react module which is explicitly named React, and import that here as a constant that I want to call React."

in profiel.js add default keyword to export :
export default class GebruikerScherm extends React.Component {...
and also recheck all related paths in imports of screens.

Related

React Native Redux - Not showing updated state via different route

I'm writing a react-native app via expo and trying to implement redux. I'm not sure if I'm going about this completely the wrong way. I have a home page that has two sections, a search text box and an area with links to content pages. The content pages also contain the same search box component. I want to be able to pass the contents of the search box input to the content page so that the user doesn't need to enter this again (and will probably require access to this content further in the user journey)
My app.js looks like the below:
import React from 'react';
import 'react-native-gesture-handler';
import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
import ContentPage from './pages/ContentPage.js';
import LogoTitle from './components/LogoTitle';
import EventsListPage from './pages/EventsListPage.js';
import EventPage from './pages/EventPage';
import VenuePage from './pages/VenuePage';
import HomeScreen from './pages/HomePage';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
const initialState ={
postcode:"abcefg"
}
const reducer = (state = initialState, action) => {
switch(action.type)
{
case 'SET_POSTCODE':
return {
postcode: action.text
}
default:
console.log("returning default state")
return state
}
}
const store = createStore(reducer);
const RootStack = createStackNavigator(
{
Home: HomeScreen,
ContentPage: ContentPage,
EventsListPage: EventsListPage,
EventPage: EventPage,
VenuePage: VenuePage
},
{
initialRouteName: 'Home',
defaultNavigationOptions: {
headerTitle: () => <LogoTitle />,
headerLeft: () => null,
headerStyle: {
backgroundColor: '#ADD8E6'
}
},
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<AppContainer />
</Provider>);
}
}
Homepage.js:
import React from 'react';
import { StyleSheet, View } from 'react-native';
import SearchBox from '../components/SearchBox'
import TypeDrillDownArea from '../components/TypeDrillDownArea'
import 'react-native-gesture-handler';
class HomeScreen extends React.Component {
constructor(props) {
super(props);
state = {
};
}
render() {
return (
<View style={styles.container}>
<SearchBox navigation={this.props.navigation} eventTypeId=''/>
<TypeDrillDownArea navigation={this.props.navigation} />
</View>
);
}
}
export default HomeScreen
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'stretch'
},
});
Relevant searchbox.js:
render() {
return (
<ImageBackground source={topperBackground} style={{width: '100%'}}>
<View>
<View style={styles.row}>
<View>
<TextInput
value={this.props.postcode}
autoCapitalize="characters"
style={styles.inputBox}
placeholder="Enter Postcode"
onChangeText={(e) => this.props.setPostcode(e)}
/>
</View>
<View>
<TouchableOpacity
disabled={this.state.locationDisabled}
onPress={() => {
this.props.navigation.navigate('EventsListPage', {
navigation: this.props.navigation,
eventTypeId: this.state.eventTypeId,
locLongitude: this.state.location.coords.longitude,
locLatitude: this.state.location.coords.latitude,
});
}}>
<Image
style={styles.locationPin}
source={locationPin}
/>
</TouchableOpacity>
</View>
</View>
<View style={styles.searchButtonArea}>
<TouchableOpacity
onPress={() => {
console.log("postcode is: " + this.state.postcode)
this.props.navigation.navigate('EventsListPage', {
eventTypeId: this.state.eventTypeId,
postcode: this.props.postcode,
});
}}>
<Text style={styles.searchButton}>SEARCH</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SearchBox)
function mapStateToProps(state){
return {
postcode:state.postcode
}
}
function mapDispatchToProps(dispatch){
return{
setPostcode : (e) => dispatch({
type: 'SET_POSTCODE',
postcode : e
})
}
}
and finally relevant contentpage.js:
<View style={styles.container}>
<SearchBox navigation={this.props.navigation} eventTypeId={this.state.eventTypeId} />
<Image source={imageType(this.state.dataSource[0].eventTypeId)} style={styles.eventType} />
<Text style={styles.textToDisplay}>
{this.state.dataSource[0].eventTypeDescription}
</Text>
</View>
On load, the box is prepopulated with "abcefg" as expected. Changing the contents hits the reducer as expected. However when I navigate to a content page which loads the search box again the value is empty, regardless if I've changed the original state or not.
Am I missusing redux for what it's intended? Should I be doing this a different way?
For clarity below is the organisation of the components
In the reducer(), you are accessing action.text but in the dispatch(), you passed postcode value to postcode instead of text.

FlatList Render issue in react-navigation

I am trying to render a FlatList in the home screen using react-navigation after refresing this error message appears:
invariant violation: Objects are not valid as a React child (found: object with keys {screenProps, navigation}). If you meant to render a collection of children, use an array instead.
//App.js
import React from 'react';
import Navigator from './src/Routes/appRoutes';
import { View, Text, StyleSheet } from 'react-native';
import TodoApp from './src/todoApp';
import SingleTodo from './src/components/singleTodo';
const App = () => {
return (
<Navigator />
);
}
const styles = StyleSheet.create(
{
container: {
padding: 40
}
}
)
export default App;
//FlatList screen
import React, { useState } from 'react';
import { View, FlatList } from 'react-native';
import Todos from './components/todos';
import uuid from 'uuid';
const TodoApp = () => {
const [todo, setTodo] = useState([
{
id: uuid(),
title: "FFFFFFFFF",
desc: "first description"
},
{
id: uuid(),
title: "Second title",
desc: "Second description"
}
]
)
return (
<View>
<FlatList
data={todo}
renderItem={({ item }) =>
<Todos title={item.title} desc={item.desc} />}
keyExtractor={item => item.id}
/>
</View>
);
}
export default TodoApp;
//Routes
import { createStackNavigator } from 'react-navigation-stack';
import Todos from './../components/todos';
import SingleTodo from './../components/singleTodo';
import { createAppContainer } from 'react-navigation';
import { Settings } from './../settings';
const screens = {
Home: {
screen: Todos
},
SingleTodo: {
screen: SingleTodo
}
}
const StackScreens = createStackNavigator(screens);
export default createAppContainer(StackScreens);
//Todos screen
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import { NavigationNativeContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const Todos = (props) => {
console.log(props);
const { title, desc } = props;
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => props.navigation.navigate('SingleTodoScreen')}>
<View>{props}</View>
<Text style={styles.listText}>{title}</Text>
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
container: {
padding: 15,
color: "#000",
borderWidth: 1,
borderColor: "#eee",
},
listText: {
fontSize: 16
}
});
export default Todos;
You need to remove the following line from the code
<View>{props}</View>
props is an object, and you can not write the include the object in your JSX.
So your functional component will be like this.
const Todos = (props) => {
console.log(props);
const { title, desc } = props;
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => props.navigation.navigate('SingleTodoScreen')}>
<Text style={styles.listText}>{title}</Text>
</TouchableOpacity>
</View>
)
}

What's causing React Native componentDidMount being called none stop, indefinitely?

Here is the App.js
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View } from 'react-native';
import MovieList from './MovieList';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<MovieList />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
}
});
Here is the MoveList.js
import React, { Component } from 'react';
import { Platform, StyleSheet, FlatList, ActivityIndicator, Text, View } from 'react-native';
export default class MovieList extends Component {
constructor(props){
super(props);
this.state ={ isLoading: true}
}
componentDidMount() {
console.log("componentDidMount")
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
// console.log("responseJson: " + JSON.stringify(responseJson))
this.setState({
isLoading: false,
dataSource: responseJson.movies,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
render(){
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return(
<View style={styles.container}>
<FlatList
data={this.state.dataSource}
renderItem={({item}) => <Text>{item.title}, {item.releaseYear}</Text>}
keyExtractor={({id}, index) => id}
/>
<MovieList name='Valeera' />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
}
});
The code for downloading the movie is from the official getting started tutorial networking, the only differences is that I put the code in a new js file called MovieList and include it as a component in the App.js
With the above code, the componentDidMount is being called none stop, and printing the movie list indefinitely, and eventually the app will crash.
Isn't the componentDidMount supposed to be called only once? What's causing it to be called indefinitely? What did I do wrong in the above code?
You are having your component MovieList embedded in the render-method of the component itself. This is creating the endless loop. Probably you only need to remove it there as your FlatList seems complete.

TypeError: Cannot read property 'navigate' of undefined

I wrote a snapshot test for a screen called NewUser.js, here is the test code:
import React from "react";
import NewUser from "../app/screens/NewUser/NewUser"
import renderer from "react-test-renderer"
describe("<NewUser/>", ()=>{
it("snapshot", ()=>{
expect(renderer.create(<NewUser/>).toJSON()).toMatchSnapshot();
});
});
And here is the NewUser.js
import React, { Component } from 'react';
import { StyleSheet, Text, View, Button} from 'react-native';
import styles from './Styles'
export default class NewUser extends Component {
static navigationOptions = () => {
return {
headerStyle: styles.headerStyle,
headerTintColor: '#fff',
headerTitle: 'JetSet',
headerTitleStyle: {
flex: 1,
}
};
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.background}>
<View style={styles.container}>
<Button
onPress={() => navigate('Survey', { survey: 'NewUserQuestions' })}
title="New User"
/>
</View>
</View>
);
}
}
I got the error when I run the test. What should I do to make test runnable? Thanks.
I somehow solved it by doing this
{ navigation } = this.props
...navigation.navigate()
I am still not sure the reason caused that issue, and the solution is not perfect, but it saved my code.

add onPress to first component and call it on second component

I'm a beginner in react-native I want to make add ( + ) button on the header of the first component when user click on onPress it will create a new form and the form is the second component
In App.js SetUp Navigation like below:
import { createAppContainer, createStackNavigator } from "react-navigation";
import MainScreen from "./screens/MainScreen";
import SecondScreen from "./screens/SecondScreen";
const AppNavigator = createStackNavigator({
MainScreen: {
screen: MainScreen
},
SecondScreen: {
screen: SecondScreen,
},
})
const App = createAppContainer(AppNavigator);
export default App;
In Main Screen
import React, { Component } from "react";
import {
View,
Button,
} from "react-native";
class MainScreen extends Component {
handleOnPress = () => {
this.props.navigation.navigate("SecondScreen");
};
render() {
return (
<View>
<Button
onPress={this.handleOnPress}
title="Button"
color="#841584"
/>
</View>
);
}
}
export default MainScreen;
It will redirect you to second screen
You can set ref of Form component
<FormsComponent
ref={ref => {
this.formComponent = ref;
}}
/>
You should pass function as prop for Header component
<HeaderComponent addNewForm={this.addNewForm} />
Parent component will call function of form component when click in header component using ref
addNewForm = () => {
this.formComponent.addNewForm();
};
App Preview
Complete Code
import React, { Component } from "react";
import { View, Text, FlatList } from "react-native";
class HeaderComponent extends Component {
render() {
return (
<View style={{ height: 80, backgroundColor: "red", paddingTop: 24 }}>
<Text style={{ padding: 20 }} onPress={this.props.addNewForm}>
Call Function of Form Component
</Text>
</View>
);
}
}
class FormsComponent extends Component {
addNewForm = () => {
alert("add new form");
};
render() {
return (
<FlatList
data={[{ key: "Form1" }, { key: "Form2" }]}
renderItem={({ item }) => <Text>{item.key}</Text>}
style={{ flex: 1 }}
/>
);
}
}
export default class App extends Component {
addNewForm = () => {
this.formComponent.addNewForm();
};
render() {
return (
<View style={{ flex: 1 }}>
<HeaderComponent addNewForm={this.addNewForm} />
<FormsComponent
ref={ref => {
this.formComponent = ref;
}}
/>
</View>
);
}
}