I'm using react-navigation to navigte my android app, I use react-navigation with redux.
App.js:
const AppRouteConfigs = {
Home: {
screen: HomeView
},
Completed: {
screen: CompletedView
}
}
export const AppNavigator = TabNavigator(AppRouteConfigs,{
tabBarPosition: 'bottom',
tabBarOptions: {
showIcon: true
}
});
#connect(state=>({
nav: state.nav
}))
class App extends Component {
componentDidMount(){
SplashScreen.hide();
}
render(){
return (
<AppNavigator navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav
})}/>
)
}
}
export default App;
reducer:
const initialNavState = {
index: 1,
routes: [
{key: 'InitB',routeName: 'Completed'},
{key: 'InitA',routeName: 'Home'}
]
}
export default function(state=initialNavState,action){
switch(action.type) {
case 'Login':
return AppNavigator.router.getStateForAction(NavigationActions.back(),state);
case 'Logout':
return AppNavigator.router.getStateForAction(NavigationActions.navigate({routeName: 'Completed'}),state)
default:
return state;
}
}
HomeView:
#connect(state=>({
todos: state.todos
}))
export default class HomeView extends Component{
constructor(props){
super(props);
}
static navigationOptions = {
tabBarLabel: 'Home View',
tabBarIcon: ({tintColor})=>(
<Icon name="rocket" size={15} color="#900" />
)
}
handleClick = ()=>{
this.props.dispatch(NavigationActions.navigate({routeName: 'Completed'}))
}
render(){
return (
<View>
<Text>Hey,I'm home page</Text>
<Button onPress={this.handleClick} title="go to completed"/>
<Icon name="rocket" size={30} color="#900" />
</View>
)
}
}
in the Home view, I want to navigate to Completed view,
this.props.dispatch(NavigationActions.navigate({routeName: 'Completed'}))
doesn't work, I don't know why.
this.props.navigation.dispatch(NavigationActions.navigate({routeName: 'Completed'}))
doesn't work, either.
Try this one:
render() {
const { navigate } = this.props.navigation
return (
<View>
<Button
onPress={() => navigation.navigate('Completed')}
title='Completed'
/>
</View>
)
}
Related
Hi I'm trying to make an Instagram clone with react-redux Firebase react navigation etc.
Now I'm stuck on displaying the Users's information like name and email.
I don't know what's wrong with the code, but I get this error.
The Profile code:
import React from 'react'
import { StyleSheet, View, Text, Image, FlatList } from 'react-native'
import { connect } from 'react-redux';
function Profile(props) {
const{ currentUser, posts } = props;
console.log({ currentUser, posts })
return (
<View style={styles.container}>
<View style={styles.containerInfo}>
<Text> {currentUser.name} </Text>
<Text> {currentUser.email} </Text>
</View>
<View style={styles.containerGallery}>
<FlatList
numColumns={3}
horizontal={false}
data={posts}
renderItem={({item}) => (
<Image
style={styles.image}
source={{uri: item.downloadURL}}
/>
)}
/>
</View>
</View>
)
}
const styles = StyleSheet.create({
container:{
flex: 1,
marginTop: 40,
},
containerInfo:{
margin: 20,
},
containerGallery:{
flex:1,
},
image:{
flex: 1,
aspectRatio: 1/1
}
})
const mapStateToProps = (store) => ({
currentUser: store.userState.currentUser,
posts: store.userState.posts,
})
export default connect(mapStateToProps, null)(Profile);
The Login code:
import { ThemeProvider } from '#react-navigation/native';
import React, { Component } from 'react'
import { ViewBase, Button, TextInput, View } from 'react-native'
import firebase from 'firebase';
export class Login extends Component {
constructor(props){
super(props);
this.state = {
email: '',
passwort: '',
}
this.onSignUp = this.onSignUp.bind(this)
}
onSignUp(){
const { email, password, name } = this.state;
firebase.auth().signInWithEmailAndPassword(email, password)
.then((result) =>{
console.log(result)
})
.catch((error) =>{
console.log(error)
})
}
render() {
return (
<View>
<TextInput
placeholder="email"
onChangeText={(email) => this.setState({ email })}
/>
<TextInput
placeholder="password"
secureTextEntry={true}
onChangeText={(password) => this.setState({ password })}
/>
<Button
onPress={() => this.onSignUp()}
title="Sing in"
/>
</View>
)
}
}
export default Login
The user code:
import { USER_STATE_CHANGE, USER_POSTS_STATE_CHANGE } from "../constants"
const initalState = {
currentUser: null,
posts: []
}
export const user = (state = initalState, action) => {
switch(action.type){
case USER_STATE_CHANGE:
return {
...state,
currentUser: action.currentUser
}
case USER_POSTS_STATE_CHANGE:
return {
...state,
posts: action.posts
}
default:
return state
}
}
The register code:
import { USER_STATE_CHANGE, USER_POSTS_STATE_CHANGE } from "../constants"
const initalState = {
currentUser: null,
posts: []
}
export const user = (state = initalState, action) => {
switch(action.type){
case USER_STATE_CHANGE:
return {
...state,
currentUser: action.currentUser
}
case USER_POSTS_STATE_CHANGE:
return {
...state,
posts: action.posts
}
default:
return state
}
}
Index.js:
import { combineReducers } from 'redux'
import { user } from './user'
const Reducers = combineReducers({
userState: user
})
export default Reducers
I really don't know what you all need to see from the code to help me but if I need to update the post with more information please let me know, don't block the post!
THANK YOU
Your problem is connected to the fact that currentUser does not have a valid value when component is rendered. You have several ways to solve this:
conditional rendering: put a condition on html:
<View style={styles.containerInfo}>
{currentUser && <Text> {currentUser.name} </Text>}
{currentUser && <Text> {currentUser.email} </Text>}
</View>
use ? operator:
<View style={styles.containerInfo}>
<Text> {currentUser?.name} </Text>
<Text> {currentUser?.email} </Text>
</View>
import { copilot, walkthroughable, CopilotStep } from 'react-native-copilot';
class DashboardContent extends Component {
state ={
secondStepActive: true
};
componentDidMount() {
this.props.start()
this.props.copilotEvents.on('stepChange', this.handleStepChange);
}
handleStepChange = step => {
console.log(`Current step is: ${step.name}`);
};
render() {
return (
<View> ...... <View/>
);
}
}
export default copilot({
animated: true,
overlay: 'svg',
})(DashboardContent);
I am using the react-native-copilot library for a walkthrough. I wish to trigger the this.props.start() function which starts the walkthrough using a button from my NavBar component - The _infoPage function in the code below should trigger the function basicaly.
The code for the Navbar is :
class NavBar extends Component {
state ={
isModalVisible: false,
email:'',
emailError: false,
emailErrorMessage: '',
};
_profileEdit() {
Actions.profileedit();
}
_notificationsPage(){
Actions.notifications();
}
_infoPage = () =>{
this.props.toggleTour();
}
toggleModal = () => {
this.setState({isModalVisible: !this.state.isModalVisible});
};
render() {
const {index, routes} = this.props.tabs;
console.log(index);
return (
<SafeAreaView>
<View style={styles.container}>
<StatusBar />
<TouchableOpacity onPress={this._infoPage}>
<MaterialCommunityIcons name="information-outline" size={24} color="#979797" style={{padding:10}}/>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
}
function mapStateToProps(state){
return {
tabs : state.tabs
}
}
function mapDispatchToProps(dispatch){
return {
changeCounter : (index) => dispatch({type:'PAGE_CHANGED',payload: index}),
toggleTour: () => dispatch({
type: 'TOUR_OPENED'
})
}
}
export default connect(mapStateToProps, mapDispatchToProps)(NavBar);
I was thinking of putting this.props.start() inside a function and calling the function from another component.
How do I go about this?
Here is my App.js
export default class App extends Component {
render() {
return (
<Provider store = {store}>
<Routes />
</Provider>
);
}
}
The call for the NavBar is in Routes:
export default class Routes extends Component {
render() {
return (
<Router navBar={TopNavbar}>
<Scene key="root">
...
</Scene>
</Router>
);
}
}
You could pass the function as a prop in the other component, for example in your render function you could do the following:
render() {
return (
<View>
<YourComponent startTutorial={this.props.start}></YourComponent>
</View>
);
}
Then in YourComponent call this.props.startTutorial(); from a button or any event.
** Update
So in your case you can do the following:
export default class App extends Component {
render() {
return (
<Provider store = {store}>
<Routes /*here*/ startTutorial={this.props.start} />
</Provider>
);
}
}
export default class Routes extends Component {
/*here*/
CTopNavbar = ({ children }) => (
<TopNavbar startTutorial={this.props.startTutorial}>
{children}
</TopNavbar>
);
render() {
return (
<Router navBar={/*here*/CTopNavbar}>
<Scene key="root">
...
</Scene>
</Router>
);
}
}
Then in NavBar run this.props.startTutorial(); in your button.
I am using react-navigation for routing between screens. Now, the scenario is I have used SwitchNavigator for authentication.
Example:
SplashScreen
this.props.navigation.navigate(userToken? 'App' : 'Auth', { extraParams: value});
LoginScreen / Home Screen
this.props.navigation.state.params.extraParams
This returns only routeName and key. Please find the reference code that I am using.
import React from 'react';
import {
ActivityIndicator,
AsyncStorage,
Button,
StatusBar,
StyleSheet,
View,
} from 'react-native';
import { createStackNavigator, createSwitchNavigator, createAppContainer } from 'react-navigation';
class SignInScreen extends React.Component {
static navigationOptions = {
title: 'Please sign in',
};
render() {
return (
<View style={styles.container}>
<Button title="Sign in!" onPress={this._signInAsync} />
</View>
);
}
_signInAsync = async () => {
await AsyncStorage.setItem('userToken', 'abc');
this.props.navigation.navigate('App');
};
}
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome to the app!',
};
render() {
return (
<View style={styles.container}>
<Button title="Show me more of the app" onPress={this._showMoreApp} />
<Button title="Actually, sign me out :)" onPress={this._signOutAsync} />
</View>
);
}
_showMoreApp = () => {
this.props.navigation.navigate('Other');
};
_signOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
}
class OtherScreen extends React.Component {
static navigationOptions = {
title: 'Lots of features here',
};
render() {
return (
<View style={styles.container}>
<Button title="I'm done, sign me out" onPress={this._signOutAsync} />
<StatusBar barStyle="default" />
</View>
);
}
_signOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
}
class AuthLoadingScreen extends React.Component {
constructor() {
super();
this._bootstrapAsync();
}
// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
const userToken = await AsyncStorage.getItem('userToken');
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
this.props.navigation.navigate(userToken ? 'App' : 'Auth');
};
// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
const AppStack = createStackNavigator({ Home: HomeScreen, Other: OtherScreen });
const AuthStack = createStackNavigator({ SignIn: SignInScreen });
export default createAppContainer(createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
));
Can anyone please help to get an appropriate solution to pass extra params from SplashScreen to HomeScreen or LoginScreen?
I am trying to navigate between the screens. I installed npm react-navigation for this purpose. I am trying to go back from my AutoCompActivity page to app.js page. I have the following code on my AutoCompActivity page:
import HomeActivity from '../App'
class AutocompActivity extends Component {
constructor(props) {
super(props);
this.state = {
// Default Value of this State.
Loading_Activity_Indicator: true,
text:'',
selected_topic_id: -1,
}
this.arrayholder=[];
}
OpenHomePageFunction = () =>
{
this.props.navigation.navigate('Home');
}
and finally, I have this in my code:
export default MyNewProject= StackNavigator(
{
Home: {screen:HomeActivity}
}
I am getting the below error:
My AutoCompActivity.js resides inside a folder called Module, module reside inside the root folder' and app.js resides into the root folder of application.
Below is my App.js code:
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View, Button, Image, TouchableOpacity,Platform } from 'react-native';
import { StackNavigator } from 'react-navigation';
import MissionActivity from './Modules/MissionActivity' ;
import AutoCompActivity from './Modules/AutoCompActivity' ;
import SearchServices from './Modules/SearchServices';
class MainActivity extends Component {
constructor(){
super();
this.state={
isVisible : true,
}
}
Hide_Splash_Screen=()=>{
this.setState({
isVisible : false
});
}
componentDidMount(){
var that = this;
setTimeout(function(){
that.Hide_Splash_Screen();
}, 5000);
}
static navigationOptions = {
title: '',
};
OpenSecondActivityFunction = () =>
{
this.props.navigation.navigate('Mission');
}
OpenThirdActivityFunction = () =>
{
this.props.navigation.navigate('autoComp');
}
OpenSearchSer = () =>
{
this.props.navigation.navigate('SearchSer');
}
render()
{
let Splash_Screen = (
<View style={styles.SplashScreen_RootView}>
<View style={styles.SplashScreen_ChildView}>
{/* Put all your components Image and Text here inside Child view which you want to show in Splash Screen. */}
<Image source={require('./Resources/CAC.png')}
style={{width:'100%', height: '100%', resizeMode: 'contain'}} />
</View>
<TouchableOpacity
activeOpacity = { 0.5 }
style={styles.TouchableOpacity_Style}
onPress={this.Hide_Splash_Screen} >
<Image source={{uri: 'https://reactnativecode.com/wp-content/uploads/2018/01/close_button.png'}}
style={{width:25, height: 25}} />
</TouchableOpacity>
</View> )
return(
<View style = { styles.MainContainer }>
<View style={styles.toolbar}>
<Image
resizeMode='contain'
style={styles.toolbarTitle}
source={require('./Resources/LogoWithDesc.jpg')} />
</View>
<View>
<Image
style={styles.title}
source={require('./Resources/Pot.png')} />
</View>
<View style={styles.searchButton}>
<Button onPress = { this.OpenSecondActivityFunction } title = 'Mission'/>
</View>
<View style={styles.searchButton}>
<Button onPress = { this.OpenThirdActivityFunction } title = 'Available Services'/>
</View>
{
(this.state.isVisible === true) ? Splash_Screen : null
}
</View>
);
}
}
export default ActivityProject = StackNavigator(
{
First: { screen: MainActivity, navigationOptions:{header:null} },
Mission: { screen: MissionActivity },
SearchSer: { screen: SearchServices },
autoComp:{screen: }
});
My React Js skills are very basic,What I want to get is when I click on a category, I show a list of posts of the category selected in a new screen in this case is PostsScreen.
The problem is that i get the itemId null.
I don't know what i'm doing wrong.
These are my screens and the routes component
Categories Screen
import React, {Component} from 'react';
import { NavigationActions, DrawerNavigator, StackNavigator } from 'react-navigation';
import{Dimensions, Button, View, SafeAreaView, FlatList, ActivityIndicator, TouchableOpacity } from 'react-native';
export default class WGoals extends Component {
static navigationOptions = {
title: 'Categories'
};
navigateToScreen = (route, params) => () => {
const navigateAction = NavigationActions.navigate({
routeName: route,
params: params
});
this.props.navigation.dispatch(navigateAction);
}
constructor(props)
{
super(props);
this.state = {
isLoading: true,
}
}
render() {
return (
<Container style={styles.background_general}>
<TouchableOpacity onPress={this.navigateToScreen('PostsScreen', itemId = '1')} >
<Text>Category 1</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.navigateToScreen('PostsScreen', itemId = '2')} >
<Text>Category 2</Text>
</TouchableOpacity>
</Container>
);
}
}
Posts Screen
import React, {Component} from 'react';
import { NavigationActions, DrawerNavigator, StackNavigator } from 'react-navigation';
import{Dimensions, View, SafeAreaView, FlatList, ActivityIndicator } from 'react-native';
export default class Posts extends Component {
static navigationOptions = {
title: 'Posts'
};
render() {
const { params } = this.props.navigation.state;
const itemId = params ? params.itemId : null;
return (
<Container style={styles.background_general}>
<Text>Details Screen</Text>
<Text>itemId: {JSON.stringify(itemId)}</Text>
</Container>
);
}
}
Routes
import React from 'react';
import CategoriesScreen from '../screens/Categories';
import PostsScreen from '../screens/Posts';
import SideMenu from './SideMenu';
import {DrawerNavigator, StackNavigator} from 'react-navigation'
const navigationOptions = {
navigationOptions: {
headerStyle: {
backgroundColor: '#f39c12',
},
headerTitleStyle: {
textAlign: 'center',
alignSelf: 'center',
fontSize: 20,
color: '#fff',
fontWeight: 'bold'
}
}
};
const leftIcon = (navigation, icon) => <Icon
name={icon}
style={{marginLeft: 20}}
size={20}
color="white"
onPress={() => navigation.navigate('DrawerOpen')}
/>;
const rightIcon = (navigation, icon) => <Icon
name={icon}
style={{marginLeft: 20}}
size={30}
color="white"
onPress={() => navigation.navigate('CategoriesScreen')}
/>;
const CategoriesScreenStack = StackNavigator (
{
Categories: {
screen: CategoriesScreen,
navigationOptions: ({navigation}) => ({
drawerIcon: ({tintColor}) => (<Icon name="home" size={24} style={{color: '#f39c12'}} />),
headerLeft: leftIcon(navigation, 'menu')
})
}
},
navigationOptions
);
const PostsScreenStack = StackNavigator(
{
PostsScreen: {
screen: PostsScreen,
navigationOptions: ({ navigation }) => ({
drawerIcon: ({ tintColor }) => (<Icon name="user" size={24} style={{ color: tintColor }} />),
headerLeft: leftIcon(navigation, 'menu')
})
}
},
navigationOptions
);
export default DrawerNavigator({
CategoriesScreen: {
screen: CategoriesScreenStack
},
PostsScreen: {
screen: PostsScreenStack
},
}, {
contentComponent: SideMenu,
drawerWidth: width * .7,
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
});
You want to pass itemId in an object to navigateToScreen, since you are accessing params as an object (params.itemId) in WorkoutsGoalsList, currently it is undefined.
Also, onPress expects a function reference. As it is now, you are actually calling the function so this.navigateGateToScreen will be called on every render. Check out the bind documentation, bind allows you to create a new function with a specific list of arguments:
render () {
return (
<Container style={styles.background_general}>
<TouchableOpacity
onPress={this.onPress.bind(this, '1')}
>
<Text>Category 1</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.onPress.bind(this, '2')}
>
<Text>Category 2</Text>
</TouchableOpacity>
</Container>
);
};
onPress = (id) => {
this.navigateToScreen('PostsScreen', { itemId: id })
};
You also do not need to curry your navigateToScreen function:
navigateToScreen = (route, params) => { // remove curry here
const navigateAction = NavigationActions.navigate({
routeName: route,
params: params,
});
this.props.navigation.dispatch(navigateAction);
};
Your props will look something like this:
this.props = {
navigation: {
state: {
params: {
itemId: '1',
}
}
}
};
It's less than optimal to bind in render because a new function will be created on every render call. A better way to structure the code is to create a dedicated component and pass an itemId and onPress function:
WGoals
export default class WGoals extends Component {
static navigationOptions = {
title: 'Categories',
};
navigateToScreen = (route, params) => {
const navigateAction = NavigationActions.navigate({
routeName: route,
params: params,
});
this.props.navigation.dispatch(navigateAction);
};
constructor(props) {
super(props);
this.state = {
isLoading: true,
};
}
render() {
return (
<Container style={styles.background_general}>
<Category name='Category1' onPress={this.navigateToScreen} itemId='1' />
<Category name='Category2' onPress={this.navigateToScreen} itemId='2' />
</Container>
);
}
}
Category
export default class Category extends Component {
render () {
const { name } = this.props;
return (
<TouchableOpacity
onPress={this.handlePress}
>
<Text>{name}</Text>
</TouchableOpacity>
);
}
handlePress = () => {
const { itemId, onPress } = this.props;
onPress('PostsScreen', { itemId: itemId });
}
}
In PostsScreens, you need to render itemId in a string or you can render the value of the variable by wrapping it in curly brackets ({itemId}). Below, I'm rendering it as a string and inserting the value of itemId into the string. Check out the template literal docs for more info on the syntax:
export default class Posts extends Component {
static navigationOptions = {
title: 'Posts',
};
render() {
const { params } = this.props.navigation.state;
const itemId = params ? params.itemId : null;
return (
<Container style={styles.background_general}>
<Text>'Details Screen'</Text>
<Text>`itemId: ${itemId}`</Text>
</Container>
);
}
}