react native stack navigation undefined is not an object (evalutating 'props.navigation') - react-native

‌‌I'm making an app in react-native and I would like to navigate to different page by clicking on a button using stack navigation:
Here is my code :
app.js
import React from 'react';
import { AppRegistry } from 'react-native';
import { StackNavigator } from 'react-navigation';
import Home from './Screens/Home';
import VideoListItems from './Screens/VideoListItems';
import TrackPlayer from './Screens/TrackPlayer';
const reactNavigationSample = props => {
return <VideoListItems navigation={props.navigation} />;
};
reactNavigationSample.navigationOptions = {
title: "VideoListItems"
};
const AppNavigator = StackNavigator({
Home: { screen: Home, navigationOptions: { header: null }},
VideoListItems: { screen: VideoListItems, navigationOptions: { header: null }},
TrackPlayer: { screen: TrackPlayer, navigationOptions: { header: null }},
}
);
export default class App extends React.Component {
render() {
return (
<AppNavigator />
);
}
}
VideoListItems where the button to navigate is :
import {StackNavigator} from 'react-navigation';
const VideoListItems = ({ video, props }) => {
const { navigate } = props.navigation;
const {
cardStyle,
imageStyle,
contentStyle,
titleStyle,
channelTitleStyle,
descriptionStyle
} = styles;
const {
title,
channelTitle,
description,
thumbnails: { medium: { url } }
} = video.snippet;
const videoId = video.id.videoId;
return(
<View>
<Card title={null} containerStyle={cardStyle}>
<Image
style={imageStyle}
source= {{ uri: url}}
/>
<View style={contentStyle}>
<Text style={titleStyle}>
{title}
</Text>
<Text style={channelTitleStyle}>
{channelTitle}
</Text>
<Text style={descriptionStyle}>
{description}
</Text>
<Button
raised
title="Save And Play"
icon={{ name: 'play-arrow' }}
containerViewStyle={{ marginTop: 10 }}
backgroundColor="#E62117"
onPress={() => {
navigate('TrackPlayer')
}}
/>
</View>
</Card>
</View>
);
};
export default VideoListItems;
But I'm getting this error :
TypeError: undefined is not an object (evaluating 'props.navigation')
I don't know how to pass the props navigation and make it able to navigate when clicking on the button, I don't know where is my error, any ideas ?
[EDIT]
My new VideoItemList :
const VideoListItems = props => {
const {
cardStyle,
imageStyle,
contentStyle,
titleStyle,
channelTitleStyle,
descriptionStyle
} = styles;
const {
title,
channelTitle,
description,
thumbnails: { medium: { url } }
} = props.video.snippet;
const videoId = props.video.id.videoId;
const { navigate } = props.navigation;
return(
<View>
<Card title={null} containerStyle={cardStyle}>
<Image
style={imageStyle}
source= {{ uri: url}}
/>
<View style={contentStyle}>
<Text style={titleStyle}>
{title}
</Text>
<Text style={channelTitleStyle}>
{channelTitle}
</Text>
<Text style={descriptionStyle}>
{description}
</Text>
<Button
raised
title="Save And Play"
icon={{ name: 'play-arrow' }}
containerViewStyle={{ marginTop: 10 }}
backgroundColor="#E62117"
onPress={() => {
navigate.navigate('TrackPlayer')
}}
/>
</View>
</Card>
</View>
);
};
This is the file where I display all my components :
import React, { Component } from 'react';
import { View } from 'react-native';
import YTSearch from 'youtube-api-search';
import AppHeader from './AppHeader';
import SearchBar from './SearchBar';
import VideoList from './VideoList';
const API_KEY = 'ApiKey';
export default class Home extends Component {
state = {
loading: false,
videos: []
}
componentWillMount(){
this.searchYT('');
}
onPressSearch = term => {
this.searchYT(term);
}
searchYT = term => {
this.setState({ loading: true });
YTSearch({key: API_KEY, term }, videos => {
console.log(videos);
this.setState({
loading: false,
videos
});
});
}
render() {
const { loading, videos } = this.state;
return (
<View style={{ flex: 1, backgroundColor: '#ddd' }}>
<AppHeader headerText="Project Master Sound Control" />
<SearchBar
loading={loading}
onPressSearch={this.onPressSearch} />
<VideoList videos={videos} />
</View>
);
}
}
And my VideoList where I use VideoListItems :
import React from 'react';
import { ScrollView, View } from 'react-native';
import VideoListItems from './VideoListItems';
const VideoList = ({ videos }) => {
const videoItems = videos.map(video =>(
<VideoListItems
key={video.etag}
video={video}
/>
));
return(
<ScrollView>
<View style={styles.containerStyle}>
{videoItems}
</View>
</ScrollView>
);
};
const styles = {
containerStyle: {
marginBottom: 10,
marginLeft: 10,
marginRight: 10
}
}
export default VideoList;

That's because you try to extract navigation from a prop named props (that doesn't exist), you have many ways to solve this problem :
Use the rest operator to group all props except video inside a props variable
const VideoListItems = ({ video, ...props }) => {
Don't destructure you props object
const VideoListItems = props => {
// don't forget to refactor this line
const videoId = props.video.id.videoId;
Extract navigation from props
const VideoListItems = ({ video, navigation }) => {
const { navigate } = navigation;

Related

undefined is no an object( evaluating _this props.navigation.navigate) when i try to navigate after validate

when i trying to navigate after validate to a listdata it show up with erro as my title
? please help i'm newbie in react native. many appreciate from me thank you guys
Btw my code is kinda weird any recommend for me to boost it up? for better performance and easier to understand?
Here all my code below:
/// import code stuff
const listData = [
{
tenhs: "nguyen quang ha",
lop: "12b",
gioitinh: "nam"
},
{
tenhs: "nguyen hoag sn",
lop: "11b",
gioitinh: "nam"
},
]
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
input: {
username: null,
email: null,
password: null,
confirm_password: null,
},
errors: {
username: null,
email: null,
password: null,
confirm_password: null,
},
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit = (event) => {
if (this.validate()) {
console.log(this.state);
this.setState((prevState) => {
let input = Object.assign({}, prevState.input);
input.username = null;
input.password = null;
input.email = null;
input.confirm_password = null;
return { input };
});
this.setState((prevState) => {
let errors = Object.assign({}, prevState.errors);
errors.username = null;
errors.password = null;
errors.email = null;
errors.confirm_password = null;
return { errors };
});
this.props.navigation.navigate('listData');
}
}
/// validate code stuff
render() {
return (
<View style={{flex:1, justifyContent:'center', alignItems:'center',backgroundColor: '#00ffff',}}>
<View style={{padding:5}}>
///screen code stuff
<TouchableOpacity
onPress={(e)=>{this.handleSubmit(e);}}
style={{
///some styles code
}}>
<Text
style={{
some styles code
}}>
Đăng Ký
</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
here is Listdata screen code
import React, { Component } from 'react';
import {
Text,
Alert,
TouchableOpacity,
Button,
TextInput,
View,
StyleSheet,
} from 'react-native';
import { hScale, vScale, fScale } from "react-native-scales";
import styles from '../one/Styles';
const Listdata = [
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
title: "NguyenHoangSon",
},
{
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
title: "NguyenHoangSon",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d72",
title: "NguyenHoangSon",
},
];
export default Listdata;
There are many things to fix on your code, i will try my best to help you understand how navigation works.
Live Working Example: https://codesandbox.io/s/admiring-hugle-ey1yj?file=/src/screens/DetailsScreen.js
You have to setup your navigation correctly on App.js
You have specify the components which you want to navigate, eg: HomeScreen , DetailsScreen
Screens should return a JSX element, not an array.
Below is an simple example to understand how to navigation between screens.
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
//Screen 1
const HomeScreen = ({ navigation }) =>
{
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
//Screen 2
const DetailsScreen = () =>
{
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
}
//App.js
const App = () =>
{
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;

Unable to store data in redux store

i am trying to build a react-native app in that user can add a routine or daily task in EditRoutine.js file and it can be seen in RoutineOverviewScreen.js and i am using redux for storing these data and using hooks for storing and fetching data.
Below is the EditRoutine.js code snippet
import React, { useState, useEffect, useCallback } from "react";
import { View, StyleSheet, Text, TextInput, ScrollView } from "react-native";
import { HeaderButtons, Item } from "react-navigation-header-buttons";
import Card from "../components/Card";
import { useSelector, useDispatch } from "react-redux";
import * as routinesActions from "../store/actions/routine";
import Routine from "../models/routine";
import HeaderButton from "../components/HeaderButton";
const EditRoutine = (props) => {
const dispatch = useDispatch();
const [title, setTitle] = useState("");
const [detail, setDetail] = useState("");
const [time, setTime] = useState("");
const submitHandler = useCallback(() => {
dispatch(routinesActions.createRoutine(title, detail, time));
props.navigation.goBack();
}, [dispatch,title, detail, time]);
useEffect(() => {
props.navigation.setParams({ submit: submitHandler });
}, [submitHandler]);
return (
<Card style={styles.container}>
<Text>Title</Text>
<TextInput
style={styles.input}
value={title}
onChangeText={(text) => setTitle(text)}
/>
<Text>Details</Text>
<TextInput
style={styles.input}
multiline
numberOfLines={4}
value={detail}
onChangeText={(text) => setDetail(text)}
/>
<Text>Time</Text>
<TextInput
style={styles.input}
value={time}
onChangeText={(text) => setTime(text)}
/>
</Card>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
padding: 10,
width: "100%",
},
input: {
paddingHorizontal: 2,
borderBottomColor: "#ccc",
borderBottomWidth: 1,
width: "100%",
marginVertical: 15,
},
});
EditRoutine.navigationOptions = (navData) => {
const submitFn = navData.navigation.getParam("submit");
return {
headerTitle: "Edit Routine",
headerTitle: "Your Routines",
headerLeft: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Menu"
iconName={
Platform.OS === "android" ? "md-arrow-back" : "ios-arrow-back"
}
onPress={() => {
navData.navigation.goBack();
}}
/>
</HeaderButtons>
),
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Save"
iconName={
Platform.OS === "android" ? "md-checkmark" : "ios-checkmark"
}
onPress={submitFn}
/>
</HeaderButtons>
),
};
};
export default EditRoutine;
and this is my RoutineOverviewScreen.js file where i am trying to show the created routine
import React from "react";
import { View, StyleSheet, Text, FlatList } from "react-native";
import Card from "../components/Card";
import { HeaderButtons, Item } from "react-navigation-header-buttons";
import HeaderButton from "../components/HeaderButton";
import { useSelector } from "react-redux";
const RoutineOverViewScreen = (props) => {
const routines = useSelector((state) => state.routines.myRoutine);
return (
<FlatList
data={routines}
keyExtractor={(item) => item.id}
renderItem={(itemData) => (
<Card>
<View>
<Text>{itemData.item.id} </Text>
</View>
<View>
<Text>{itemData.item.title} </Text>
</View>
<View>
<Text>{itemData.item.detail} </Text>
<View>
<Text>{itemData.item.time} </Text>
</View>
</View>
</Card>
)}
/>
);
};
const styles = StyleSheet.create({});
RoutineOverViewScreen.navigationOptions = (navData) => {
return {
headerTitle: "Your Routines",
headerLeft: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Menu"
iconName={Platform.OS === "android" ? "md-menu" : "ios-menu"}
onPress={() => {
navData.navigation.toggleDrawer();
}}
/>
</HeaderButtons>
),
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Add"
iconName={
Platform.OS === "android" ? "md-add-circle" : "ios-add-circle"
}
onPress={() => {
navData.navigation.navigate("Edit");
}}
/>
</HeaderButtons>
),
};
};
export default RoutineOverViewScreen;
Below is my action file routine.js snippet
export const CREATE_ROUTINE= 'CREATE_ROUTINE';
export const deleteRoutine = routineId => {
return { type: DELETE_ROUTINE, pid: routineId };
};
export const createRoutine = (title, detail, time) => {
return {
type: CREATE_ROUTINE,
routineData: {
title,
detail,
time
}
};
};
Below is my reducer file reducer.js snippet
import {
DELETE_ROUTINE,
CREATE_ROUTINE,
UPDATE_ROUTINE,
} from "../actions/routine";
import Routine from "../../models/routine";
const initialState = {
myRoutine: {},
id: 1,
};
export default (state = initialState, action) => {
switch (action.type) {
case CREATE_ROUTINE:
const newRoutine = new Routine(
state.id,
action.routineData.title,
action.routineData.detail,
action.routineData.time
);
return {
...state,
items: { ...state.items, [state.id]: newRoutine },
id: state.id + 1,
};
default: {
return state;
}
}
return state;
};
and this is my app.js file snippet
import React, { useState } from 'react';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { AppLoading } from 'expo';
import * as Font from 'expo-font';
import routinesReducer from './store/reducers/routine';
import AppNavigator from './navigator/RoutineNavigator';
const rootReducer = combineReducers({
routines: routinesReducer,
});
const store = createStore(rootReducer);
const fetchFonts = () => {
return Font.loadAsync({
'open-sans': require('./assets/fonts/OpenSans-Regular.ttf'),
'open-sans-bold': require('./assets/fonts/OpenSans-Bold.ttf')
});
};
export default function App() {
const [fontLoaded, setFontLoaded] = useState(false);
if (!fontLoaded) {
return (
<AppLoading
startAsync={fetchFonts}
onFinish={() => {
setFontLoaded(true);
}}
/>
);
}
return (
<Provider store={store}>
<AppNavigator />
</Provider>
);
}
with these above code i am able to create a new routine but i am not knowing whether my input are getting stored in to the App central state because when i am trying to render those saved data i am unable to see in my RoutineOverviewScreen screen.please help me and
About Me: Govind Kumar Thakur ( iamgovindthakur )
email: iamgovindthakur#gmail.com
Thank You :)
You are trying to use the data of "myRoutine" but never save data to this property in the reducer.
I think that the issue you are having is due to the following line in your reducer:
items: { ...state.items, [state.id]: newRoutine },

How to separate API call using react natives context API?

I am new to react native. I have following component in my project for now I have written for fetching API in same component but want to separate it out. I am getting difficulty for how can i access variable which I am using in "getAlbum" method from outside of component.
I am trying to do this using new concept context API . is this possible using context API and how?
Is there standard way to separate API call from component?
import React, { Component } from 'react';
import {
FlatList, Text, View, Image, TouchableOpacity,
} from 'react-native';
import { ActivityIndicator, Provider } from 'react-native-paper';
import axios from 'axios';
import styles from '../style/ThumbnailView.component.style';
import ErrorAlert from '../common/ErrorAlert';
import * as myConstant from '../common/Constants';
export default class HomeScreen extends Component {
// For to Navigation header
static navigationOptions = () => ({
headerTitle: 'Album Information',
});
constructor(props) {
super(props);
this.state = {
isLoading: true,
apiLoadingError: false,
};
}
getAlbums() {
const { navigation } = this.props;
const albumId = navigation.getParam('albumID', 'no data');
axios
.get(
myConstant.API + `photos?albumId=${albumId}`, {timeout: myConstant.TIMEOUT}
)
.then((response) => {
this.setState({
isLoading: false,
dataSource: response.data,
});
})
.catch(err => {
this.setState({isLoading: false, apiLoadingError: true})
});
}
componentDidMount() {
this.getAlbums();
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, paddingTop: 30 }}>
<ActivityIndicator animating={true} size='large' />
</View>
);
}
if (this.state.apiLoadingError) {
return (
<ErrorAlert />
);
}
return (
<React.Fragment>
<Provider>
<View style={styles.listContainer} >
<FlatList
testID='flatlist'
data={ this.state.dataSource } numColumns={3}
renderItem={({ item }) => <View style={styles.listRowContainer}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('AlbumDetailsViewScreen', {
albumTitle: item.title, albumImg: item.url
})} style={styles.listRow}>
<View style={styles.listTextNavVIew}>
<Image source = {{ uri: item.thumbnailUrl }} style={styles.imageViewContainer} />
</View>
</TouchableOpacity>
</View>
}
keyExtractor = { (item, index) => index.toString() }
/>
</View>
</Provider>
</React.Fragment>
);
}
}

How to navigate other component when use bind()?

I use react-navigation to navigate other component.
Now i want to navigate to other component with some params(selectedCity、firstSliderValue、secondSliderValue), but onAccept() function will get the error
TypeError: Cannot read property 'bind' of undefined
When i added the params before, i can navigate to my MovieClostTime component. Why i can not add params ? What should i do ?
Any help would be appreciated. Thanks in advance.
Here is my part of code:
constructor(props) {
super(props);
this.state = {
showModal: false,
selectedCity: 'Keelung',
firstSliderValue: 18,
secondSliderValue: 21
};
}
// it will close <Confirm /> and navigate to MovieCloseTime component
onAccept() {
this.setState({ showModal: !this.state.showModal });
const { selectedCity, firstSliderValue, secondSliderValue } = this.state;
console.log(selectedCity); // Keelung
console.log(firstSliderValue); // 18
console.log(secondSliderValue); // 21
this.props.navigation.navigate('MovieCloseTime', {
selectedCity,
firstSliderValue,
secondSliderValue
});
}
// close the Confirm
onDecline() {
this.setState({ showModal: false });
}
render() {
if (!this.state.isReady) {
return <Expo.AppLoading />;
}
const movies = this.state.movies;
console.log('render FirestScrren');
return (
<View style={{ flex: 1 }}>
{/* Other View */}
{/* <Confirm /> is react-native <Modal />*/}
<Confirm
visible={this.state.showModal}
onAccept={this.onAccept.bind(this)}
onDecline={this.onDecline.bind(this)}
onChangeValues={this.onChangeValues}
>
</Confirm>
</View>
);
}
My Confirm.js
import React from 'react';
import { Text, View, Modal } from 'react-native';
import { DropDownMenu } from '#shoutem/ui';
import TestConfirm from './TestConfirm';
import { CardSection } from './CardSection';
import { Button } from './Button';
import { ConfirmButton } from './ConfirmButton';
const Confirm = ({ children, visible, onAccept, onDecline, onChangeValues }) => {
const { containerStyle, textStyle, cardSectionStyle } = styles;
return (
<Modal
visible={visible}
transparent
animationType="slide"
onRequestClose={() => {}}
>
<View style={containerStyle}>
<CardSection style={cardSectionStyle}>
<TestConfirm onChangeValues={onChangeValues} />
{/* <Text style={textStyle}>
{children}
</Text> */}
</CardSection>
<CardSection>
<ConfirmButton onPress={onAccept}>Yes</ConfirmButton>
<ConfirmButton onPress={onDecline}>No</ConfirmButton>
</CardSection>
</View>
</Modal>
);
};
const styles = {
// some style
};
export { Confirm };

function is not a function - react-native

In my project, I used stack navigator as the navigator. Inside navigationOptions, at headerRight, I used a custom button. When I try to call the onPress, it says the function is not a function.
this is the function
sharePost() {
// this.props.doShare();
console.log("DONE");
}
I have put the full code here. I want to use sharePost function inside the rightHeader of navigationOptions.
import React, { Component } from "react";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import {
View,
Text,
Image,
TouchableOpacity,
Animated,
ScrollView,
StyleSheet,
Dimensions
} from "react-native";
import { PostProfileBar, WritePost } from "../../components";
import { ButtonWithoutBackground } from "../../mixing/UI";
const width = Dimensions.get("window").width;
const height = Dimensions.get("window").height / 3;
class SharePostScreen extends Component {
constructor(props) {
super(props);
sharePost() {
// this.props.doShare();
console.log("DONE");
}
render() {
return (
<View style={styles.container}>
<ScrollView>
<WritePost profile={this.state.loggedUserProfile} />
<View style={styles.sharePostWrapper}>
<PostProfileBar profile={this.state.postedUserProfile} />
<Image
source={{
uri: "https://pbs.twimg.com/media/DWvRLbBVoAA4CCM.jpg"
}}
resizeMode={"stretch"}
style={styles.image}
/>
</View>
</ScrollView>
</View>
);
}
static navigationOptions = ({ navigation }) => ({
headerTitle: "Share To Feed",
headerTitleStyle: {
paddingLeft: "20%",
paddingRight: "20%"
},
headerStyle: {
paddingRight: 10,
paddingLeft: 10
},
headerLeft: (
<Icon
name={"close"}
size={30}
onPress={() => {
navigation.goBack();
}}
/>
),
headerRight: (
<ButtonWithoutBackground
buttonText={styles.buttonText}
onPress={this.sharePost()}
>
Post
</ButtonWithoutBackground>
)
});
}
In order to call the class level methods inside the static method navigationOptions, you can do the following,
// Bind function using setParams
componentDidMount() {
const { navigation } = this.props;
navigation.setParams({
referencedSharePost: this.sharePost,
});
}
sharePost = (parameters) => {
// this.props.doShare();
console.log("DONE" + parameters);
}
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
//... Other Options
headerRight: (
<ButtonWithoutBackground
buttonText={styles.buttonText}
onPress={() => params.referencedSharePost("I'm passing something")}
>
Post
</ButtonWithoutBackground>
)
}
}