React-Native - Rendering Component on Button click using JSON data - react-native

I am completely new to React Native. So please apologize me for very naive questions.
I have a main screen which has a button. When the button is pressed I want to fetch data thru another component and display on the screen.
I have App.js
import React from 'react';
import { Button, View, Text } from 'react-native';
import { createAppContainer, createStackNavigator } from 'react-navigation'; // Version can be specified in package.json
import {getMovies} from "./fetchmenu.js";
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Menu"
onPress={() => {
<getMovies /> // I want to display data as a result of button press
}}
/>
</View>
</View>
);
}
}
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
And fetchmenu.js
import React from 'react';
import { FlatList, ActivityIndicator, Text, View } from 'react-native';
export default class getMovies extends React.Component {
constructor(props){
super(props);
this.state ={ isLoading: true}
}
componentDidMount(){
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((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={{flex: 1, paddingTop:20}}>
<FlatList
data={this.state.dataSource}
renderItem={({item}) => <Text>{item.title}, {item.releaseYear}</Text>}
keyExtractor={({id}, index) => id}
/>
</View>
);
}
}
How do I display the FlatList created by getMovies on HomeScreen
when the button is pressed?

In your HomeScreen set your state like this:
state={showMovies:false}
Then on Button click setState to {showMovies:true}. And in your render function in App.js:
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Menu"
onPress={() => {
this.setState({showMovies:true});
}}
/>
{this.state.showMovies&&<GetMovies/>}
</View>
</View>
);
}
Since you are exporting getMovies class as default export (not named) do the same with importing:
WRONG: import {getMovies} from "./fetchmenu.js";
CORRECT: import GetMovies from "./fetchmenu.js";
I strongly recommend you to watch some tutorials before getting into real projects.
EDIT
As #Milore stated Component names in React must start with capital letter. See this for further information

constructor(props){
super(props);
this.state ={ isLoading: true}
}
I don't see dataSource in this.state but you are using
this.setState({
isLoading: false,
dataSource: responseJson.movies,
}, function(){
});

Related

How to pass new params to previous screen in react native?

I have a flatlist of movies when a user clicks on it, it passes param to movie details screen and movie detail is shown then that screen has flatlist of similar movies when user selects any of it, basically new params should be passed to movie details screen but no, it is just working as if i am tapping on back button....
onPress={() =>
this.props.navigation.navigate('MovieDetails', {
selectedItem: item,
})
} // Passing params to movie details screen
console.log(this.props.navigation.getParam('selectedItem')) //receiving params in movie details screen
Check this below example. Hope this will help you.
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 20, marginBottom: 10 }}>Home Screen</Text>
<Button
title="Go to Details"
onPress={() =>
this.props.navigation.navigate('Details', {
name: 'this params from homescreen',
})
}
/>
</View>
);
}
}
class DetailsScreen extends React.Component {
render() {
console.log('screen', this.props.navigation.state);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 20, marginBottom: 10 }}>
{this.props.navigation.state.params.name}
</Text>
<Button
title="Go back"
onPress={() => this.props.navigation.goBack()}
/>
</View>
);
}
}
const RootStack = createStackNavigator({
Home: HomeScreen,
Details: DetailsScreen,
});
export default createAppContainer(RootStack);
Feel free for doubts.

react-navigation : passing state between screens correctly

I am trying to pass state between screen.
I followed the instructions from
Passing parameters to routes I am able to pass state from my Home screen to detail screen but when I try to pass back state from detail screen to Home screen the state is not pass.
I have agree button in Home screen and when I check on the button and navigate to detail screen, button is checked(so far good).
However, if I uncheck the button from Detail screenand navigate back to Home screen the state is stillchecked`.
Try the code from expo
This is my Home screen code:
const imageOn = require("./iconCheck.png");
const imageOff = require("./emptyCheck.png");
class HomeScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
agreeState: this.props.navigation.getParam('agreeServiceFromChild'),
};
}
checkStateImage(){
if(this.state.agreeState === undefined){this.setState({agreeState:false},()=>console.log(this.state.agreeState,'agreeState'))}
if(this.state.agreeState === true){return(imageOn)}
if(this.state.agreeState === false){return(imageOff)}
}
render() {
const { navigation } = this.props;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<CustomCheckBox
onPress={() => this.setState({agreeState: !this.state.agreeState}, ()=> console.log (this.state.agreeState,'agreeState'))}
onPressButton={() =>
this.props.navigation.navigate('Details', {
agreeServiceFromParent:this.state.agreeState,
})
}
source={this.checkStateImage()}
text='agree'
buttonText='go to DetailScreen'
/>
</View>
);
}
}
This is my Detail Screen code:
class DetailsScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
agreeState:this.props.navigation.getParam('agreeServiceFromParent'),
};
}
checkStateImage(){
if(this.state.agreeState === undefined){return(imageOff)}
if(this.state.agreeState != undefined && this.state.agreeState === true){return(imageOn)}
if(this.state.agreeState != undefined && this.state.agreeState === false){return(imageOff)}
}
render() {
const { navigation } = this.props;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<CustomCheckBox
onPress={() => this.setState({ agreeState: !this.state.agreeState}, ()=> console.log(this.state.agreeState,'agreeServiceFromChild childview'))}
source={this.checkStateImage()}
text="agree"
onPressButton={() =>
this.props.navigation.navigate('Home', {
agreeServiceFromChild:this.state.agreeState,
})
}
buttonText='go to HomeScreen'
/>
</View>
);
}
}
rather than putting in constructor , try putting it in componentDidMount() . PFB the code ive updated from expo snaack . and ive used navigation.push in place of navigation.navigate , coz push always makes an implicit push at top of navigator stack .,
import React from 'react';
import { Button, View, Text, TouchableOpacity, Image } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
const imageOn = require("./iconCheck.png");
const imageOff = require("./emptyCheck.png");
class HomeScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
agreeState: false,
};
}
componentDidMount(){
let stateOfBut = this.props.navigation.getParam('agreeServiceFromChild');
this.setState({agreeState:stateOfBut})
}
checkStateImage(){
if(this.state.agreeState === undefined){this.setState({agreeState:false},()=>console.log(this.state.agreeState,'agreeState'))}
if(this.state.agreeState === true){return(imageOn)}
if(this.state.agreeState === false){return(imageOff)}
}
render() {
const { navigation } = this.props;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<CustomCheckBox
onPress={() => this.setState({agreeState: !this.state.agreeState}, ()=> console.log (this.state.agreeState,'agreeState'))}
onPressButton={() =>
this.props.navigation.navigate('Details', {
agreeServiceFromParent:this.state.agreeState,
})
}
source={this.checkStateImage()}
text='agree'
buttonText='go to DetailScreen'
/>
</View>
);
}
}
class DetailsScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
agreeState:this.props.navigation.getParam('agreeServiceFromParent'),
};
}
checkStateImage(){
if(this.state.agreeState === undefined){return(imageOff)}
if(this.state.agreeState != undefined && this.state.agreeState === true){return(imageOn)}
if(this.state.agreeState != undefined && this.state.agreeState === false){return(imageOff)}
}
render() {
const { navigation } = this.props;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<CustomCheckBox
onPress={() => this.setState({ agreeState: !this.state.agreeState}, ()=> console.log(this.state.agreeState,'agreeServiceFromChild childview'))}
source={this.checkStateImage()}
text="agree"
onPressButton={() =>
this.props.navigation.push('Home', {
agreeServiceFromChild:this.state.agreeState,
})
}
buttonText='go to HomeScreen'
/>
</View>
);
}
}
const CustomCheckBox = ({ onPress, source, text, onPressButton, buttonText }) => (
<View
style={{
marginTop: 14,
height: 100,
width: 310,
backgroundColor: "transparent",
alignItems: "center",
justifyContent: "flex-start",
}}
>
<TouchableOpacity onPress={onPress}>
<View
style={{
marginLeft: 7,
flexDirection:'row',
backgroundColor: "white",
borderRadius: 10,
alignItems: "center",
justifyContent: "center"
}}
>
<Image style={{ width: 21, height: 21 }} source={source} />
<Text style={{ marginLeft: 8 }}>{text}</Text>
</View>
</TouchableOpacity>
<Button title={buttonText} onPress={onPressButton}/>
</View>
);
const RootStack = createStackNavigator({
Home: HomeScreen,
Details: DetailsScreen,
});
export default createAppContainer(RootStack);

React component not re-rendering on state change using setState

I have a HomeScreen component which has button. I am trying to popup a modelview(Seperate component ie PopUpView) on the button click. In PopUpView i am sending its visibility as prop (isVisible).On the click of the button i am trying to change the state value popUpIsVisible from false to true. Hoping that this would re-render and popup my model view(Note this is working fine if i explicitly pass true). However with the state change it look like the render function is not being called and the popUp is not being displayed. Thanks for your help in advance
import React from 'react';
import { View, StyleSheet, Text, Button, TouchableHighlight, Alert, Dimensions} from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import PopUpView from './src/PopUpView';
class HomeScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
popUpIsVisible: false,
};
}
setPopUpIsVisible(isVisible){
this.setState({popUpIsVisible: isVisible });
}
render() {
this.setPopUpIsVisible = this.setPopUpIsVisible.bind(this);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor:"blue" }}>
<Text>Home Screen</Text>
<PopUpView isVisible={this.state.popUpIsVisible}/>
<Button onPress={() => {this.setPopUpIsVisible(true)}} title="Open PopUp Screen"/>
</View>
);
}
}
const RootStack = createStackNavigator(
{
Home: HomeScreen
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
PopUpView.js
import React from 'react';
import { View, Modal,StyleSheet, Text, TouchableOpacity, Dimensions} from 'react-native';
import { TabView, TabBar,SceneMap } from 'react-native-tab-view';
import Icon from 'react-native-vector-icons/SimpleLineIcons';
const FirstRoute = () => (
<View style={{ flex: 1, backgroundColor: '#ff4081' }} />
);
const SecondRoute = () => (
<View style={{ flex: 1, backgroundColor: '#673ab7' }} />
);
const ThirdRoute = () => (
<View style={{ flex: 1, backgroundColor: '#673ab7' }} />
);
export default class PopUpView extends React.Component {
constructor(props) {
super(props);
this.state = {
modalVisible:this.props.isVisible,
index: 0,
routes: [
{ key: 'first', title: 'HIGHLIGHTS' },
{ key: 'second', title: 'AMENITIES' },
{ key: 'third', title: 'FACILITIES' },
],
};
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
renderHeader = props => <TabBar
{...props}
indicatorStyle={{backgroundColor: 'red'}}
tabStyle={styles.bubble}
labelStyle={styles.noLabel}
/>;
render() {
return (
<Modal
animationType="slide"
transparent={true}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={styles.container}>
<View style={styles.navBar}>
<Text style={styles.navBarTitle}>Test</Text>
<TouchableOpacity
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}>
<Icon style={styles.closeButton} name="close" size={35} color="grey" />
</TouchableOpacity>
</View>
<TabView
navigationState={this.state}
renderScene={SceneMap({
first: FirstRoute,
second: SecondRoute,
third: ThirdRoute,
})}
onIndexChange={index => this.setState({ index })}
initialLayout={{ width: Dimensions.get('window').width }}
renderTabBar={props =>
<TabBar
{...props}
style={{ backgroundColor: 'white' }}
indicatorStyle={{backgroundColor: 'black'}}
tabStyle={styles.bubble}
labelStyle={styles.label}
/>
}
/>
</View>
</Modal>
);
}
}
const styles = StyleSheet.create({
container: {
flex:1,
margin: 50,
marginLeft: 20,
marginRight: 20,
marginBottom: 20,
backgroundColor: "white",
borderWidth: 1,
borderColor: "grey",
flexDirection: 'column'
},
navBar:{
height:70,
justifyContent: 'space-between',
alignItems: 'center',
flexDirection: 'row',
borderBottomColor: 'lightgrey',
borderBottomWidth: 1,
},
navBarTitle:{
fontSize: 25,
fontFamily: 'Optima',
paddingLeft:15,
},
closeButton:{
paddingRight:12,
},
label: {
color: 'black'
}
})
The problem with your code is that you are using the state inside the PopUpView which does not change when you change the external prop. to fix this you should use the componentwillreceiveprops and update your state accordingly.
componentWillReceiveProps(nextProps){
if(this.props.isVisible!=nextProps.isVisible){
this.setState({modalVisible:nextProps.isVisible})
}
}
The better approach will be using the this.props.isVisible as the visible prop for the Model.
In this scenario you will have to pass a function as a prop to popupview which will set the popUpIsVisible to false.
Something like below
<PopUpView isVisible={this.state.popUpIsVisible}
onDismiss={()=>{this.setState({popUpIsVisible:false})}}/>
You can call the onDismiss inside the child as
<Modal visible={this.props.isVisible}>
<TouchableHighlight
onPress={() => {
this.props.onDismiss();
}}>
<Text>Hide Modal</Text>
</TouchableHighlight>
</Modal>
The second approach is better as the visibility of the child is controlled by the parent.
Add below line into constructor after state defining
this.setPopUpIsVisible = this.setPopUpIsVisible.bind(this);

react native, moving between screens

I am using stackNavigator in react native .my problem is I want to move to another screen using stack navigator.
app.js
const CartStack=createStackNavigator({
Header:Header,
Cart:Cart
)}
Const Root=createStackNavigator({
Home:Home,
Detail:Detail,
CartStack:CartStack,
)}
Home.js
render() {
return (
<Header/>
)}
The Header Will be show on both screens (Home and Detail)
in the header i created a cart button which i want to click on
it then will be open a Cart screen. But my code is not working.
Please correct my code.
The concept in Zayco's answer is absolutely correct.
But I figured out that this.props.navigation.navigate will be undefined in navigationOptions
Here is the working example of your requirement.
class Home extends React.Component {
static navigationOptions = ({navigation}) => ({
title: 'Home',
headerRight:(<Button title="Cart" onPress={() => navigation.navigate('Cart')}/>)
})
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Scree</Text>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details')}
/>
</View>
);
}
}
class Details extends React.Component {
static navigationOptions = ({navigation}) => ({
title: 'Details',
headerRight:(<Button title="Cart" onPress={() => navigation.navigate('Cart')}/>)
})
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details</Text>
</View>
);
}
}
class Cart extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Cart</Text>
</View>
);
}
}
const RootStack = createStackNavigator(
{
Home: Home,
Details: Details,
Cart:Cart
},
{
initialRouteName: 'Home',
}
);
This is taken from the React Navigation documentation
You have 3 screens: Home, Details and Cart. In the header of Home and Details you have a button that will take you to the Cart screen. I suggest you take a look at the Fundementals section of the documentation.
Here is the working Snack
import React from "react";
import { View, Text, Button } from "react-native";
import { createStackNavigator, createAppContainer } from "react-navigation";
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => ({
headerTitle: "Home",
headerRight: (
<Button
onPress={() => navigation.navigate('Cart')}
title="Cart"
color="blue"
/>
)
});
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Home Screen</Text>
<Button
onPress={() => this.props.navigation.navigate('Details')}
title="Go to details"
color="red"
/>
</View>
);
}
}
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation }) => ({
headerTitle: "Details",
headerRight: (
<Button
onPress={() => navigation.navigate('Cart')}
title="Cart"
color="blue"
/>
),
});
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Details Screen</Text>
<Button
onPress={() => this.props.navigation.navigate('Home')}
title="Go to home"
color="red"
/>
</View>
);
}
}
class CartScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Cart Screen</Text>
</View>
);
}
}
const AppNavigator = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
Cart: CartScreen
},
{
initialRouteName: "Home"
}
);
export default createAppContainer(AppNavigator);

when Modal set to hide, the status bar will flicker

here is code: and i want to know if it is a issue? or , whether it is a universal phenomenon.
'use strict';
import React, {Component} from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Modal
} from 'react-native';
import NavActivity from '../components/NavActivity';
class TestPage extends Component {
constructor(props) {
super(props);
this.state = {
modalVisible: false
}
}
_setModalVisible(param) {
this.setState({modalVisible: param});
}
render() {
return (
<View style={Styles.wrap}>
<NavActivity
navigator={this.props.navigator}
title={{
title: '测试页面'
}}/>
<TouchableOpacity
onPress={() => this.setState({modalVisible: true})}>
<Text>show modal</Text>
</TouchableOpacity>
<Modal
animationType={'fade'}
transparent={true}
visible={this.state.modalVisible}
onRequestClose={() => {
this._setModalVisible(false)
}}>
<View style={Styles.container}>
<Text>Modal!!!</Text>
</View>
</Modal>
</View>
)
}
}
const Styles = StyleSheet.create({
wrap: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-start',
alignItems: 'center',
},
container: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0,0,0,0.7)'
},
});
export default TestPage;
environment:
react native version: 0.40
android version: 7.1.1
the gif explain everything, and this phenomenon confuse me whether should i continue to use Modal component.
Use This 'react-native-modal' library.
import React, { Component } from 'react'
import { Text, TouchableOpacity, View } from 'react-native'
import Modal from 'react-native-modal'
export default class ModalTester extends Component {
state = {
isModalVisible: false
}
_showModal = () => this.setState({ isModalVisible: true })
_hideModal = () => this.setState({ isModalVisible: false })
render () {
return (
<View style={{ flex: 1 }}>
<TouchableOpacity onPress={this._showModal}>
<Text>Show Modal</Text>
</TouchableOpacity>
<Modal isVisible={this.state.isModalVisible}>
<View style={{ flex: 1 }}>
<Text>Hello!</Text>
</View>
</Modal>
</View>
)
}
}
For more docs read from here:-
https://github.com/react-native-community/react-native-modal
this issue fixed in RN 0.45, see the release doc enter link description here
bug fixed.