Hi I am new to react native and I am facing strange issue with routing. I am doing something wrong but need someone to guide me.
index.android.js
import { LandingScreen } from './src/components/landing_screen.js'
import HomeScreen from './src/app_component.js'
import { StackNavigator } from 'react-navigation';
const SimpleApp = StackNavigator({
Home: { screen: HomeScreen },
Landing: { screen: LandingScreen},
});
AppRegistry.registerComponent('HomeScreen', () => SimpleApp);
app_component.js
// Other imports ...
export default class HomeScreen extends Component {
static navigationOptions = {
title: 'Home Screen',
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}> Hello CHannoo!!!</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Double tap R on your keyboard to reload,{'\n'}
Shake or press menu button for dev menu
</Text>
<Button
title="Go to 2nd Page"
onPress={() =>
// alert('hello');
navigate('LandingScreen')
// navigate('Home', { name: 'Jane' })
}
/>
</View>
);
}
componentDidMount () {
SplashScreen.close({
animationType: SplashScreen.animationType.scale,
duration: 850,
delay: 500,
})
}
}
landing_screen.js
export default class LandingScreen extends Component {
static navigationOptions = {
title: 'Landing Screen Title',
};
render() {
return (........)
}
It works fine if we remove route Landing. But when we add this route we get error.
Route 'Landing' should declare a screen. For example ......
Your LandingScreen has been exported as default but you imported it by name.
your import statement is like this:
import { LandingScreen } from './src/components/landing_screen.js'
replace it with line below (without curly brackets):
import LandingScreen from './src/components/landing_screen.js'
it should solve the problem.
BUT you will probably get a new error as #Medet pointed out because you have to change this line:
navigate('LandingScreen')
to:
navigate('Landing')
since your screen name is Landing.
You calling navigate('LandingScreen')
But screen name is Landing
+ #Dusk's answer should solve
Related
Hey I have a search screen "search for songs/artists" So after sending the request i want to appear a "Top Tabs", So I add a Top tab "createMaterialTopTabNavigator" inside separate files and then import it as a component to use it inside Search Screen like this <SearchTabs /> But i got an error
Invariant Violation: The navigation prop is missing for this
navigator. In react-navigation v3 and v4 you must set up your app
container directly. More info:
https://reactnavigation.org/docs/en/app-containers.html
lib
"react-navigation": "^4.1.0",
"react-navigation-drawer": "^2.3.3",
"react-navigation-stack": "^2.0.16",
"react-navigation-tabs": "^2.7.0",
Top Tabs Code
import {createMaterialTopTabNavigator} from 'react-navigation-tabs';
import resultArtists from './resultArtists';
import resultSongs from './resultSongs';
const SearchTabNavigator = createMaterialTopTabNavigator(
{
Songs: {
screen: resultSongs,
navigationOptions: {
tabBarLabel: 'Songs',
},
},
Artists: {
screen: resultArtists,
navigationOptions: {
tabBarLabel: 'Artists',
},
},
},
);
export default SearchTabNavigator;
then i import it in createStackNavigator 'Root.js Navigation file' like this
SearchTabs: {
screen: SearchTabNavigator,
},
here's Search Code "That contains input then i want to appear the top tabs"
class Search extends PureComponent {
render() {
return (
<Container style={styles.container}>
<View style={styles.searchHeader}>
<Input
onChangeText={text => this.search(text)}
value={this.state.searchText}
onSubmitEditing={this.onSearch}
returnKeyType="search"
placeholderTextColor="white"
style={styles.searchInput}
/>
</View>
<SearchTabNavigator />
</Container>
)
}
}
export default Search;
The final result should be something like this
What I tried
I add new createAppContainer to wrap the Top tabs like this in 'Top Tabs file'
export const Tabs = createAppContainer(SearchTabNavigator);
And it's working fine.
but i think it's the wrong way, to add two AppContainer in the same app :\
And when i want to navigate from any item "songs" to Player screen 'it's in Different AppContainer' it's not working!.
App.js
<Store>
<Navbar />
<AppNavigator ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}} />
</Store>
I wanna be able to access
props.navigation.openDrawer();
from navbar but I get
undefined is not an object (evaluating 'props.navigation.openDrawer')
onPress
Navbar.js:70:29
etc..
How can I allow NavBar to access the drawer?
I suppose you are following Navigating without the navigation prop (if you don't then you should in your case). Then in NavigationService.js add openDrawer method
// NavigationService.js
import { DrawerActions } from 'react-navigation-drawer';
...
// add this function
function openDrawer(routeName, params) {
_navigator.dispatch(DrawerActions.openDrawer());
}
export default {
...
// and export it
openDrawer
};
then instead of props.navigation.openDrawer(), use
NavigationService.openDrawer()
don't forget to make respective imports
this is how i used openDrawer without navigation prop:
in your App.js (or other router)
1/
import { DrawerActions } from '#react-navigation/native';
2/
export const navigationRef = React.createRef();
3/
export function openDrawer(routeName, params) {
navigationRef.current.dispatch(DrawerActions.openDrawer());
}
4/ inside your navigation container add this ref
<NavigationContainer ref={navigationRef}>
5/ call your function somewhere where openDrawer is created:
<TouchableOpacity onPress={() => openDrawer()}>
<Image
source={tab}
style={{
width: 20,
height: 20,
}}
/>
</TouchableOpacity>
Hi Please see my code Here :
https://snack.expo.io/#ersimransingh/navigation-problem
I have created my switch navigator to navigate between pages from App.js to Second.js
On App.js page I have imported Second.js file module named App1 Which works file.
Moreover, I did the same thing on Second.js file imported App component from App.js But swith navigator show error on the page says
The component for route 'App' must be a React component.
I did search on internet for the same, and tried replacing my imporing syntax from
import {App} from './App';
to
import App from './App';
You can Check my code on expo
https://snack.expo.io/#ersimransingh/navigation-problem
You have App.js which is creating a route using Second.js and Second.js is creating a route using App.js. This is definitely problematic, because you are creating a cicular reference. Rather, you should create your navigation in one place and use it in the App.js
Here is an example:
App.js
export default class App extends React.Component{
render(){
return(
<CreateTag />
);
}
}
const AppContainer = createSwitchNavigator({
FirstScreen,
SecondScreen
});
const CreateTag = createAppContainer(AppContainer);
FirstScreen.js
export default class FirstScreen extends React.Component {
render() {
let { navigation } = this.props;
return (
<View>
<Text
style={styles.sampleText}
onPress={() => navigation.navigate('SecondScreen')}>
First screen
</Text>
</View>
);
}
}
SecondScreen.js
export default class SecondScreen extends React.Component {
render() {
let { navigation } = this.props;
return (
<View>
<Text
style={styles.sampleText}
onPress={() => navigation.navigate('FirstScreen')}>
Second screen
</Text>
</View>
);
}
}
Here is the complete example: https://snack.expo.io/S1cY9IVEV
Also you can check from the official example: https://github.com/react-navigation/react-navigation/blob/master/examples/NavigationPlayground/js/App.js
I hope this helps.
I am trying to load my parent component from child component on button press. But it's not rendering the parent components from btnPress method. I am not getting any error.
onButtonPress
<Button onPress={() => btnPress(parent_id, id)}>
<Icon name="arrow-forward" />
</Button>
btnPress Function
function btnPress(parent_id, id) {
const App = () => (
//I have tried this way but this didn't work. No any error, i can see log on console
<Container>
<Headerc headerText={'Fitness sdaf'} />
<ExerciseList pId={parent_id} mId={id} />
</Container>
);
console.log(id);
AppRegistry.registerComponent('weightTraining', () => App);
}
full code(child component)
import React from 'react';
import { Right, Body, Thumbnail, Container, ListItem, Text, Icon } from 'native-base';
import { AppRegistry
} from 'react-native';
import Headerc from './headerc';
import ExerciseList from './exerciseList';
import Button from './Button';
const ExerciseDetail = ({ exercise }) => {
const { menu_name, menu_icon, parent_id, id } = exercise;
function NumberDescriber() {
let description;
if (menu_icon === 'noimg.jpg') {
description = `http://www.xxxxxx.com/uploads/icons/${menu_icon}`;
} else if (menu_icon === 'noimg.jpg') {
description = menu_icon;
} else {
description = `http://www.xxxxx.com/uploads/icons/${menu_icon}`;
}
return description;
}
function btnPress(parent_id, id) {
const App = () => (
<Container>
<Headerc headerText={'Fitness sdaf'} />
<ExerciseList pId={parent_id} mId={id} />
</Container>
);
console.log('-------------------------------');
console.log(id);
console.log('+++++++++++++++++++++++++++');
AppRegistry.registerComponent('weightTraining', () => App);
}
return (
<ListItem>
<Thumbnail square size={80} source={{ uri: NumberDescriber() }} />
<Body>
<Text>{menu_name}</Text>
<Text note> {menu_name} exercise lists</Text>
</Body>
<Right>
<Button onPress={() => btnPress(parent_id, id)}>
<Icon name="arrow-forward" />
</Button>
</Right>
</ListItem>
);
};
export default ExerciseDetail;
Please do let me know, if you need more information.
I would not suggest doing that way, it look totally anti-pattern and not.
better try with navigation or create a pattern like this
inside your index.js or index.android.js or index.ios.js
import App from './App' //your app level file
AppRegistry.registerComponent('weightTraining', () => App);
now in your app js file
export default App class extends React.Component{
constructor(props){
super(props);
this.state ={
component1:false,
component2:true,
}
}
btnPressed =()=>{
//handle state update logic here
}
render(){
if(this.state.component1) return <Component1/>
return <Component2/>
}
}
**** not the best solution available, play around and you will get best
To navigate from this component to your parent component unless you want to implement your own navigation which isn't recommended, you should look into one that's already built and adopted by many in the react-native ecosystem.
Some of the biggest ones:
React Native Navigation
React Navigation
React Native Router
I personally highly recommend option number 1, since it seems to be the most production tested and production ready implementation out there
I'm trying to make a simple quiz app in React Native:
App.js
export default class App extends React.Component {
constructor(props) {
super(props);
this.quizData = [
{
question: 'Who wrote A Game Of Thrones?',
correctAnswer: 'George RR Martin',
possibleAnswers: ['JK Rowling', 'Phillip Pulman', 'George RR Martin' ]
},
];
}
render() {
return (
<View style={styles.container}>
<MultiChoice answers={this.quizData[0].possibleAnswers}/>
</View>
);
}
}
And my MultiChoice component:
import React, { Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
class MultiChoice extends Component {
render() {
return(
<View>
<Text style={styles.button}>{ this.props.answers.map(answer => answer) }</Text>
</View>
)
}
}
const styles = StyleSheet.create({
button: {
backgroundColor: 'blue',
width: 200,
height: 40,
}
})
export default MultiChoice;
I don't get any errors and all the elements of the array are displayed in the same button, but I would like to have three separate buttons. I wrote the same code in React and it worked, but in React Native it is not working.
Currently, your map just returns each element, unmodified -- it does nothing. It will then create one single <Text> component with all the text. Just have the map operation return a separate <Text> component for every element to achieve separate buttons:
{ this.props.answers.map(answer => <Text style={styles.button}>{answer}</Text>) }
And this will create separate <Text> components with the strings.