I have an issue with react-navigation in passing the props to another screen,
I need to pass some props to Detail screen when the user presses one of the List Places I need to push screen with some details about the place like a Name of place and Image of place,
Errors :
this is my Code
Reducer
import { ADD_PLACE, DELETE_PLACE } from "../actions/actionTypes";
const initialState = {
places: []
};
import placeImage from "../../assets/img.jpg";
const reducer = (state = initialState, action) => {
switch (action.type) {
case ADD_PLACE:
return {
...state,
places: state.places.concat({
key: Math.random(),
name: action.placeName,
// image: placeImage,
image: {
uri:
"https://images.unsplash.com/photo-1530009078773-9bf8a2f270c6?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80"
}
})
};
case DELETE_PLACE:
return {
...state,
places: state.places.filter(place => {
return place.key !== state.selectedPlace.key;
})
};
default:
return state;
}
};
export default reducer;
Place List Component
import React from "react";
import { FlatList, StyleSheet, ScrollView } from "react-native";
import ListItem from "../ListItem/ListItem";
const PlaceList = props => {
return (
<FlatList
style={styles.listContainer}
data={props.places}
renderItem={info => (
<ListItem
placeName={info.item.name}
placeImage={info.item.image}
onItemPressed={() => props.onItemSelected(info.item.key)}
/>
)}
keyExtractor={index => String(index)}
/>
);
};
export default PlaceList;
Find Place Screen
import React, { Component } from "react";
import { View, Text } from "react-native";
import { connect } from "react-redux";
import { StackActions } from "react-navigation";
import PlaceList from "../../Components/PlaceList/PlaceList";
class FindPlaceScreen extends Component {
constructor() {
super();
}
itemSelectedHandler = key => {
const selPlace = this.props.places.find(place => {
return place.key === key;
});
this.props.navigation.push("PlaceDetail", {
selectedPlace: selPlace,
name: selPlace.name,
image: selPlace.image
});
};
render() {
return (
<View>
<PlaceList
places={this.props.places}
onItemSelected={this.itemSelectedHandler}
/>
</View>
);
}
}
const mapStateToProps = state => {
return {
places: state.places.places
};
};
export default connect(mapStateToProps)(FindPlaceScreen);
Place Details Screen
import React, { Component } from "react";
import { View, Text, Image, TouchableOpacity, StyleSheet } from "react-native";
import Icon from "react-native-vector-icons/Ionicons";
class PlaceDetail extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={styles.modalContainer}>
<View>
<Image
source={this.props.navigation.state.params.image}
style={styles.placeImage}
/>
<Text style={styles.placeName}>
{this.props.navigation.state.params.namePlace}
</Text>
</View>
<View>
<TouchableOpacity onPress={props.onItemDeleted}>
<View style={styles.deleteButton}>
<Icon size={30} name="ios-trash" color="red" />
</View>
</TouchableOpacity>
<TouchableOpacity onPress={props.onModalClosed}>
<View style={styles.deleteButton}>
<Icon size={30} name="ios-close" color="red" />
</View>
</TouchableOpacity>
</View>
</View>
);
}
}
export default PlaceDetail;
You need to use react-native-navigation v2 for the find place screen
itemSelectedHandler = key => {
const selPlace = this.props.places.find(place => {
return place.key === key;
});
Navigation.push(this.props.componentId, {
component: {
name: 'PlaceDetail',
options: {
topBar: {
title: {
text: selPlace.name
}
}
},
passProps: {
selectedPlace: selPlace
}
}
});
};
make sure you import { Navigation } from "react-native-navigation";
Your PlaceDetail has some error
<TouchableOpacity onPress={props.onItemDeleted}>
<TouchableOpacity onPress={props.onModalClosed}>
Change props to this.props
<TouchableOpacity onPress={this.props.onItemDeleted}>
<TouchableOpacity onPress={this.props.onModalClosed}>
But I don't see onItemDeleted and onModalClosed anywhere, don't forget to pass those to PlaceDetail via props as well :)
Related
I have created Table component. In this component i have created two buttons. one for download and second is share. both have onPress method. I have imported this Table component in the dashboard component. but I am unable to use both methods individually in my dashboard component.please suggest any solution for this problem.
Table Component:
import React, { StrictMode, useEffect, useState } from "react";
import { Text, View, ActivityIndicator } from "react-native";
import Size from "../../constants/Sizes";
import Strings from "../../constants/Strings";
import { Table, TableWrapper, Row, Rows } from "react-native-table-component";
import Color from "../../constants/Colors";
import Icon from "../../styles/Icons";
import api from "../../services/api";
import ListModel from "../ListModal";
import { TableTwoStyle as tableStyle } from "../../styles";
import { heightToDp } from "../../constants/Utils";
const TableTwo = (props) => {
const [files, setFiles] = useState([]);
const [modalState, setModalState] = useState(false);
useEffect(() => {
const fileData = api.getFileOptions();
setFiles(fileData);
}, []);
const { data } = props;
const handleOptions = (title) => {
console.log("title", title);
props.onPress(title);
// this.closeModal();
};
const openModal = () => {
setModalState(true);
};
const closeModal = () => {
setModalState(false);
};
return (
<StrictMode>
{data !== undefined ? (
<View style={tableStyle.mainContainer}>
<View style={tableStyle.HeadingSection}>
<View style={tableStyle.LabelContainer}>
<View style={tableStyle.leftSection}>
<Text style={tableStyle.labelText}>{Strings.tableTitle}</Text>
</View>
<View style={tableStyle.rightSection}>
<Icon.MaterialIcons
name="file-download"
color={Color.gray}
style={tableStyle.exportButton}
size={heightToDp(Size.per_4_5)}
onPress={openModal}
/>
</View>
<View style={tableStyle.rightSection}>
<Icon.MaterialIcons
name="share"
color={Color.info}
style={tableStyle.exportButton}
size={heightToDp(Size.per_4)}
onPress={openModal}
/>
</View>
</View>
<View style={tableStyle.divider} />
</View>
<View style={tableStyle.TableSection}>
{data.headers && data.headers.length > 0 ? (
<Table
borderStyle={{
borderWidth: Size.px_1,
borderColor: Color.dividerColor,
}}
>
<Row
data={data.headers}
flexArr={[Size.num_1]}
style={tableStyle.head}
textStyle={tableStyle.headerText}
/>
<TableWrapper style={tableStyle.wrapper}>
<Rows
data={data.data}
flexArr={[Size.num_1]}
style={tableStyle.row}
textStyle={tableStyle.text}
/>
</TableWrapper>
</Table>
) : (
<ActivityIndicator color={Color.loaderColor} size={Strings.lg} />
)}
</View>
<ListModel
modalState={modalState}
close={closeModal}
onPress={handleOptions}
data={files}
/>
</View>
) : null}
</StrictMode>
);
};
export default TableTwo;
Dashboard Component:
import React, { StrictMode, Component } from "react";
import { View, ScrollView } from "react-native";
import { GraphCardList as GraphList } from "../components";
import { InfoCardList as InfoList } from "../components";
import { TableTwo as Table } from "../components";
import Loader from "../components/Loader";
import Store from "../database/Storage";
import OptionsCard from "../components/Option";
import { Card as CardUI } from "../components";
import { dashboardStyle as dashboardUI } from "../styles";
import Api from "../services/api";
import inputValidation from "../helper/Validation";
import TableExport from "../exports/TableExport";
import Permission from "../services/AppPermission";
export default class DashboardScreen extends Component {
constructor(props) {
super(props);
this.state = {
tableList: [],
};
this.downloadData = this.downloadData.bind(this);
}
componentDidMount() {
}
componentWillUnmount() {
}
downloadData(title) {
...
}
shareData(){
....
}
render() {
const {
loader2,
infoList,
chartList,
tableList,
userList,
loader,
pauseState,
} = this.state;
//console.log("users",infoList);
if (loader) {
return (
<View style={dashboardUI.mainContainer}>
<Loader />
</View>
);
}
return (
<StrictMode>
<CardUI style={dashboardUI.Cards}>
<Table data={tableList} onPress={this.downloadData} />
</CardUI>
)}
</StrictMode>
);
}
}
If your'e passing same prop for two different buttons that means that the two buttons will execute the same method , but if you want to pass different methods for each button just pass a different props.
For example component B:
<View>
<Button title="Download" onPress={props.download}/>
<Button title="Share" onPress={props.share}/>
</View>
Component A:
<B download={this.downloadData} share={this.shareData}/>
Please try below code:
**In Dashboard Component:**
downloadData() {
}
`return (<Table data={tableList} handleDownloadData={this.downloadData} />);`
**In Table Component:**
const download = (data) => {
props.handleDownloadData(data);
};
const share = (data) => {
props.handleDownloadData(data);
};`
`return (<div><Button onClick={download}> Download</Button><Button onClick={share}> Share</Button></div>);
`
I'm trying to implement the react-navigation package to make one screen link to another. I'm getting an error "undefined is not an object (evaluating '_this2.props.navigation.navigate') - React Native"
I'm fairly sure this error is because I have nothing in the App.js part of my project.
I have a file called screen.js that has two classes (one for each screen), and an onpress function that calls the this.props.navigator to change screens.
Screen.js
import React, { Component } from 'react';
import {
StyleSheet,
Text,
TextInput,
View,
TouchableHighlight,
PanResponder,
AppRegistry,
Image,
Alert,
} from 'react-native';
import { Card, Button, Icon } from 'react-native-elements';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import { Constants, MapView } from 'expo';
class HomeScreen extends Component {
static navigationOptions = {
title: 'Home',
};
constructor() {
super();
this.state = {...};
}
_handleButtonPress = () => {
Alert.alert('Button pressed!', 'You did it!');
};
componentWillMount() {
this.panResponderRef = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onMoveShouldSetPanResponder: () => true,
onPanResponderGrant: this.doNothing,
onPanResponderMove: this._handlePanResponderMove,
onPanResponderRelease: this._handlePanResponderEnd,
onPanResponderTerminate: this.doNothing,
});
}
//onPanResponderRelease and onPanResponderTerminate Handler
_handlePanResponderEnd = (event, gestureState) => {
const { navigate } = this.props.navigation;
let tIndex = this.state.index;
if (this.state.dy > 100)
navigate('Second', { index: tIndex, getFunc: this.getName.bind(this) });
else if (this.state.dx > 150) this.setState({ index: tIndex + 1 });
else if (this.state.dx < -150 && tIndex > 0)
this.setState({ index: tIndex - 1 });
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<TouchableHighlight
style={styles.TouchableHighlight}
onPress={() => this.props.navigator.push({id:'SecondScreen'})}>
<View style={styles.author}>
<Text style={styles.author}>Shelter 1</Text>
</View>
</TouchableHighlight>
</View>
);
}
}
class SecondScreen extends React.Component {
static navigationOptions = {
title: 'Second',
};
constructor(props) {
super(props);
this.state = {
index: this.props.navigation.state.params.index,
getFunc: this.props.navigation.state.params.getFunc,
name: 'not set'
};
}
componentWillMount() {
let tName = this.state.getFunc(this.state.index);
this.setState({ name: tName });
}
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
</View>
<Button title="Go to Home page" onPress={() => navigate('Home')} />
</View>
);
}
}
const NavigationApp = createStackNavigator({
Home: { screen: HomeScreen },
Second: { screen: SecondScreen },
});
export default createAppContainer(NavigationApp);
});
App.js
import NavApp from "screen";
export default NavApp;
I am getting an error "undefined is not an object (evaluating '_this2.props.navigator.push')"
You could try this
this.props.navigation.push('SecondScreen')
I'm new to react-native. I use react-native-side-menu to create a drawer and I add a bottom on the left side to skip to another page. when I push the bottom, the error code appeared. However, if I put the bottom in the homepage, it works. Why if I put it in the drawer it will crash?
This is route stack
App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import HomeScene from './homeScene';
import LoginScene from './loginScene';
import RegisterScene from './registerScene';
import TimetableScene from './timetable';
import ChatScene from './ChatScene';
import LeftMenu from './LeftMenu';
const SimpleApp = createStackNavigator({
Login: {
screen: LoginScene,
navigationOptions: {
headerTitle: 'Login',
}
},
Home: {
screen: HomeScene,
navigationOptions: {
header: null,
}
},
Register: {
screen: RegisterScene,
navigationOptions: {
headerTitle: 'Register',
}
},
Timetable: {
screen: TimetableScene,
navigationOptions:{
headerTitle: 'Timetable',
}
},
//The page I want to skip
Chat: {
screen: ChatScene,
navigationOptions:{
headerTitle: 'Chat',
}
}
LeftMenu:{
screen: LeftMenu
}
});
const AppContainer = createAppContainer(SimpleApp);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
LeftScene.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity,
SectionList
} from 'react-native';
export default class LeftMenu extends Component {
constructor(props) {
super(props);
this.selectSideMenu = this.selectSideMenu.bind(this);
}
selectSideMenu() {
this.props.onSelectMenuItem();
}
Chat = () => {
const { navigate } = this.props.navigation;
navigate('Chat');
}
render() {
return (
<View style={styles.container}>
//The bottom to skip to "Chat" page but will respond error
<TouchableOpacity
onPress={this.Chat}
style={styles.button}>
<Text
style={styles.btText}>Chat</Text>
</TouchableOpacity>
</View>
);
}
}
I think maybe the wrong code from the following code in LeftScene.js
Chat = () => {
const { navigate } = this.props.navigation;
navigate('Chat');
}
The this.props can only get the value from the parent component. The parent component of LeftMenu is homeScene, homeScene has no navigation so it doesn't work. And because of App.js is parent component of homeScene, so if I put the skip bottom in homeScene it can work. But I don't know how to figure out it...
homeScene.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
TextInput,
View,
TouchableOpacity,
Dimensions
} from 'react-native';
let { width, height } = Dimensions.get('window');
import SideMenu from 'react-native-side-menu'
import Menu from './LeftMenu'
export default class LeftSideMenu extends Component {
constructor(props) {
super(props);
this.state = {
isOpen: false,
}
this.SelectMenuItemCallBack = this.SelectMenuItemCallBack.bind(this);
}
SelectMenuItemCallBack() {
this.setState({
isOpen: !this.state.isOpen,
})
}
SelectToOpenLeftSideMenu() {
this.setState({
isOpen: true,
})
}
Chat = () => {
const { navigate } = this.props.navigation;
navigate('Chat');
}
render() {
const menu = <Menu onSelectMenuItem={this.SelectMenuItemCallBack} />;
return (
<SideMenu
menu={menu}
isOpen={this.state.isOpen}
onChange={(isOpen) => {
this.setState({
isOpen: isOpen,
})
}}
menuPosition={'left'}
openMenuOffset={0.75 * width}
edgeHitWidth={200}
>
<View
style={styles.top}>
//The bottom to open the drawer
<TouchableOpacity
onPress={() => this.SelectToOpenLeftSideMenu()}
style={styles.Fbutton} >
<Text
style={styles.btText}>F</Text>
</TouchableOpacity>
</View>
//The bottom to skip to "Chat" page and works
<View style={styles.container}>
<TouchableOpacity
onPress={this.Chat}
style={styles.button}>
<Text
style={styles.btText}>Chat</Text>
</TouchableOpacity>
</View>
</SideMenu>
);
}
}
I expect the bottom to skip to "Chat" page on the homeScene can be put in the drawer
You are facing this error because your LeftScene.js is not a part of your stack just add LeftScene.js in SimpleApp.
It will work.
Just change the code in homeScene.js
const menu = <Menu onSelectMenuItem={this.SelectMenuItemCallBack} />;
to the following
const menu = <Menu onSelectMenuItem={this.SelectMenuItemCallBack} navigation={this.props.navigation} />;
I'm developing a component to publish it in npm, but I'd like to call my component using a method instead of a tag.
Example:
myComponent.js
import React from 'react'
import { View, Text } from 'react-native'
export const showComponent = () => {
// this would be the function that I user to call my component down
}
const myComponent = (props) => {
return(
<View>
<Text>Oi</Text>
</View>
)
}
App.js
import React from 'react'
import { View, Text, TouchableOpacity } from 'react-native'
import { showComponent } from 'my-component'
const App = () => {
return(
<View>
<TouchableOpacity onPress={() => showComponent()}>
<Text>Home</Text>
</TouchableOpacity>
</View>
)
}
export defaul App
the idea is that when calling the showComponent function I show my component, and when I call, for example, the hide function, I close my component.
You can do it using a single class export:
import * as React from 'react';
export default class MyComponent extends React.Component {
state = {
isOpen: false,
};
open = () => {
this.setState({ isOpen: true });
};
close = () => {
this.setState({ isOpen: true });
};
render() {
const { isOpen } = this.state;
return !isOpen ? null : (
<View>
<Text>Oi</Text>
</View>
);
}
}
And you use it like so:
<MyComponent ref={(x) => this.myComponent = x)} />
And you open it like so:
this.myComponent.open();
I see in a comment above you want to call the component with a redux action, so you should call your redux action in that on click, but the component you want to show/hide needs to be linked to a redux state variable. Then in your jsx you'd have:
<View>
<TouchableOpacity onPress={() => showComponent()}>
<Text>Home</Text>
</TouchableOpacity>
{reduxBoolean && <MyComponent />}
</View>
import React from 'react'
import { View, Text} from 'react-native'
const example = (props) => {
return (
<View>
<Text>Hello</Text>
</View>
)
}
// props
import React from 'react'
import { View, Text} from 'react-native'
const examples = () => {
return(
<View>
<Text><example/></Text>
</View>
)
}
and print is : Hello
What I want to achieve is display the datas in other screen or another component with React Redux. I'm using the latest version of React Redux and Redux.
My problem is every time I want to display the data, or when I press the button (TouchableOpacity) in EventCreator.js it doesn't display. I tried to check all of my codes but I don't see any typo or any wrong codes.
Feel free to ask for more of my codes. Thank you!
UPDATE: I tried all codes to my another new project, but with RNNV1. So it might be some new codes for RNNv2 that is related to React Redux to change. I prefer to all viewers to focus check my codes about RNNv2 connected to React Redux. Thank you!
These are my codes:
App.js, all my Registered Screens.
import {Navigation} from 'react-native-navigation';
import React from 'react';
//Screens
import AuthScreen from './src/screens/Auth/Auth';
import EventMap from './src/screens/Map/Map';
import EventCreator from './src/screens/EventCreator/EventCreator';
import EventHome from './src/screens/Home/Home';
import EventPushScreen from './src/screens/EventPushScreen/EventPushSc';
//Redux
import { Provider } from 'react-redux';
import configureStore from './src/store/configureStore';
const store = configureStore();
//Register Screens
Navigation.registerComponentWithRedux("Event.AuthScreen", () => AuthScreen);
Navigation.registerComponentWithRedux("Event.Map", () => EventMap);
Navigation.registerComponent("EventCreator", () => (props) => (
<Provider store={store}>
<EventCreator {...props}/>
</Provider>
), () => EventCreator);
Navigation.registerComponent("EventHome", () => (props) => (
<Provider store={store}>
<EventHome {...props}/>
</Provider>
), () => EventHome);
//Start A App
Navigation.events().registerAppLaunchedListener(() => {
Navigation.setRoot({
root: {
stack: {
children: [{
component: {
name: "Event.AuthScreen",
}
}],
options: {
topBar: {
title: {
text: 'Welcome',
alignment: 'center'
}
}
}
}
}
});
});
This is my 1st Screen where the TextInput and Button (TouchableOpacity) is.
EventCreator.js
import EventInput from '../../components/EventInput';
class EventCreator extends Component {
eventAddedHandler = (eventName) => {
this.props.onAddEvent(eventName);
};
render() {
return (
<View style={styles.container}>
<EventInput onEventAdded={this.eventAddedHandler}/>
</View>
);
}
};
const mapDispatchToProps = dispatch => {
return {
onAddEvent: (eventName) => dispatch(addEvent(eventName))
};
};
export default connect(null, mapDispatchToProps)(EventCreator);
EventInput.js, This is my Component that is connected to EventCreate.js
class EventInput extends Component {
state = {
eventName: ""
};
eventNameChangedHandler = (val) => {
this.setState({
eventName: val
});
};
eventSubmitHandler = () => {
if (this.state.eventName.trim() === "") {
return;
}
this.props.onEventAdded(this.state.eventName);
};
render () {
return (
<View style={styles.inputAndButtonContainer}>
<TextInput
placeholder="Create your event"
value={this.state.eventName}
onChangeText={this.eventNameChangedHandler}
style={styles.textInputContainer}
/>
<TouchableOpacity onPress={this.eventSubmitHandler}>
<View style={styles.buttonContainer}>
<Text style={{color: 'black'}}>Add</Text>
</View>
</TouchableOpacity>
</View>
);
}
};
Home.js, this is where I want to display may Data or the FlatList.
class Home extends Component {
eventSelectedHandler = key => {
const selEvent = this.props.events.find(event => {
return event.key === key;
});
Navigation.push("EventHomeStack", {
component: {
name: "EventPushScreen",
passProps: {
selectedEvent: selEvent
},
options: {
topBar: {
title: {
text: selEvent.name
}
}
}
}
});
};
render() {
return (
<View>
<EventList
events={this.props.events}
onItemSelected={this.eventSelectedHandler}
/>
</View>
);
}
};
const mapStateToProps = state => {
return {
events: state.events.events
};
};
export default connect(mapStateToProps)(Home);
EventList.js, another Component connected to Home.js
import ListItem from './ListItem';
const eventList = (props) => {
return (
<FlatList
style={styles.listContainer}
data={props.events}
renderItem={(info) => (
<ListItem
eventName={info.item.name}
eventImage={info.item.image}
onItemPressed={() => props.onItemSelected(info.item.key)}
/>
)}
/>
);
};
export default eventList;
listItem.js, another Component connected to EventList.js
const listItem = (props) => (
<TouchableOpacity onPress={props.onItemPressed}>
<View style={styles.listItem}>
<Image resizeMode="cover" source={props.eventImage} style={styles.eventImage}/>
<Text>
{props.eventName}
</Text>
</View>
</TouchableOpacity>
);
export default listItem;
events.js (reducer)
import {ADD_EVENT, DELETE_EVENT} from '../actions/actionTypes';
const initialState = {
events: []
};
const reducer = (state = initialState, action) => {
switch(action.type) {
case ADD_EVENT:
return {
...state,
events: state.events.concat({
key: `${Math.random()}`,
name: action.eventName,
image: {
uri: "https://c1.staticflickr.com/5/4096/4744241983_34023bf303_b.jpg"
}
})
};
case DELETE_EVENT:
return {
...state,
events: state.events.filter(event => {
return event.key !== action.eventKey;
})
};
default:
return state;
}
};
export default reducer;