Blank Screen with react-native navigation with no error code - react-native

Please, look at the debugger and the screen for what could be a problem. However, the code is highly displayed below for your perusal.
More also, I aimed at navigating to another page based on the id of the selected content.
App.js
The App.js is where I defined my stackNavigator
import React, {Component} from 'react';
import { StyleSheet, Text, View} from 'react-native';
import Post from './components/Post';
import PostSingle from './components/PostSingle';
import { createStackNavigator, createAppContainer } from 'react-navigation';
const RootStack = createStackNavigator(
{
PostScreen: { screen: Post},
PostSingleScreen:{screen: PostSingle},
},
{
initialRouteName: "PostScreen"
}
);
const AppNavigator = createAppContainer(RootStack);
export default class App extends Component {
constructor(props) {
super(props);
};
render() {
return (
<View style={styles.container}>
<AppNavigator/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F3F3F3',
}
});
Post.js
I have tried to delete alignItem = center. In fact I deleted my style to see if there is any blocking the screen from coming up.
import React, { Component } from 'react';
import {
ScrollView,
StyleSheet,
View,
Text,
InputText,
TouchableOpacity
} from 'react-native';
import axios from 'axios';
export default class Post extends Component{
constructor(props){
super(props);
this.state = {
posts: []
}
}
readMore = () => {
()=> this.props.navigation.navigate('PostSingleScreen');
debugger;
}
componentDidMount(){
axios.get(`http://localhost/rest_api_myblog/api/post/read.php`)
//.then(json => console.log(json.data.data[0].id))
.then(json => json.data.data.map(mydata =>(
{
title: mydata.title,
body: mydata.body,
author: mydata.author,
category_name: mydata.category_name,
id: mydata.id
}
)))
//.then(newData => console.log(newData))
.then(newData => this.setState({posts: newData}))
.catch(error => alert(error))
}
render(){
return (
<View>
<ScrollView style={styles.scrollContent}>
<View style={styles.header}>
<Text style={styles.headerText}>Gist Monger</Text>
</View>
{
this.state.posts.map((post, index) =>(
<View key={index} style={styles.container}>
<Text style={styles.display}>
Author: {post.author}
</Text>
<Text style={styles.display}>
Category: {post.category_name}
</Text>
<Text style={styles.display}>
Title: {post.title}
</Text>
<Text style={{overflow:'hidden'}}>
Id: {post.id}
</Text>
<TouchableOpacity style={styles.buttonContainer}
onPress = {() => this.readMore()}
>
<Text style={styles.buttonText}>
Read More
</Text>
</TouchableOpacity>
</View>
))
}
</ScrollView>
<View style={styles.footer}></View>
</View>
);
}
}
const styles = StyleSheet.create({
header: {
flex: 1,
height:40,
marginTop:50,
marginBottom:10,
flexDirection: 'row',
justifyContent:'center',
},
display: {
margin: 3,
fontSize: 16
},
headerText: {
fontWeight: 'bold',
fontSize: 40,
color: '#6200EE'
},
container: {
backgroundColor:'#efefef',
padding: 20,
margin: 5,
borderRadius:20,
justifyContent: 'center',
alignItems: 'center'
},
footer: {
flex: 1,
backgroundColor:'#000',
marginBottom:50
},
buttonContainer:{
height: 30,
width: 200,
marginTop: 15,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 15,
backgroundColor:'#6200EE'
},
buttonText: {
alignContent: 'center',
color: 'white'
}
});
PostSingle.js
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text
} from 'react-native';
import axios from 'axios';
export default class Post extends Component{
constructor(props){
super(props);
}
render(){
return (
<View>
<Text>My text</Text>
</View>
);
}
}
const styles = StyleSheet.create({
});

I did not test this code, but try to add flex: 1 to your container style. the main containers/components don't stretch if you don't tell them to
const styles = StyleSheet.create({
container: {
backgroundColor: '#F3F3F3',
flex: 1,
}
});
also, to check if the components render (helps debugging where the problem is), write a console log in every component's componentDidMount. if they mount, but nothing is visible, it's most likely a CSS issue. If it wasn't, it would throw errors instead of blank screen
second issue is, when you navigate you need to have params with react-navigation. the syntax for it is like this:
this.props.navigation.navigate('PostSingleScreen', { params })
so, if you have { id: someId } in your params, in the component you navigated to you will have {this.props.navigation.state.params.id}. so basically those params are inside navigation.state.params where you navigate

Let me help you with your second question. First, it is easier as said by just specifying params in your navigation.
For instance,
readMore = (id) => {
this.props.navigation.navigate('PostSingleScreen', {id:id})
}
However, in your TouchableOpacity, onPress method i.e. onPress = {() => this.readMore(post.id)}
In your PostSingle.js
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
Button
} from 'react-native';
import axios from 'axios';
class PostSingle extends Component{
constructor(props){
super(props);
this.state = {
posts: []
}
}
componentDidMount() {
const id = this.props.navigation.state.params.id;
axios.get(`http://localhost/rest_api_myblog/api/post/read_single.php?id=${id}`)
.then(json => json.data)
.then(newData => this.setState({posts: newData}))
.catch(error => alert(error))
}
render(){
return (
<View style={styles.container}>
<Text style={styles.display}>
{this.state.posts.title}
</Text>
<Text style={styles.display}>
{this.state.posts.author}
</Text>
<Text style={styles.display}>
{this.state.posts.category_name}
</Text>
<Text style={styles.display}>
{this.state.posts.body}
</Text>
</View>
);
}
}
I hope it helps

i would suggest using flaltist for this, and not this.state.map. this should give you the same outcome
readMore(id){
//do whatever you want with the id
this.props.navigation.navigate('PostSingleScreen',{id:id}); //or pass it as a prop
debugger;
}
renderItem = ({ item, index }) => {
return (
<View key={index} style={styles.container}>
<Text style={styles.display}>
Author: {item.author}
</Text>
<Text style={styles.display}>
Category: {item.category_name}
</Text>
<Text style={styles.display}>
Title: {item.title}
</Text>
<Text style={{overflow:'hidden'}}>
Id: {item.id}
</Text>
<TouchableOpacity style={styles.buttonContainer}
onPress = {() => this.readMore(item.id)}
>
<Text style={styles.buttonText}>
Read More
</Text>
</TouchableOpacity>
</View>
);
};
render(){
return (
<View style={{flex:1}}>
<FlatList
style={{flex:1}}
data={this.state.posts}
renderItem={this.renderItem}
numColumns={1}
keyExtractor={(item, index) => item.id} //this needs to be a unique id
ListHeaderComponent = {
<View style={styles.header}>
<Text style={styles.headerText}>Gist Monger</Text>
</View>}
/>
<View style={styles.footer}/>
</View>
);
}

If you are using react-navigation 5.x then it might be possible that you are adding CSS
alignItems: "center"
to your root file i.e. App.js or index.js I just removed it and it starts working for me.

Related

How to change only the active button background color [React-Native]

import React, { Component } from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
class App extends Component {
constructor(props){
super(props)
this.state={
selected:null
}
}
handle=()=>{
this.setState({selected:1})
}
render() {
return (
<View>
<TouchableOpacity style={[styles.Btn, {backgroundColor:this.state.selected===1?"green":"white"}]} onPress={this.handle}>
<Text style={styles.BtnText}>Button 1</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.Btn} onPress={this.handle}>
<Text style={styles.BtnText}>Button 2</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.Btn} onPress={this.handle}>
<Text style={styles.BtnText}>Button 3</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
Btn: {
borderWidth: 1,
width: 100,
height: 20,
borderRadius: 8,
margin: 5,
padding: 10,
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'center',
},
BtnText: {
fontSize: 15,
},
});
export default App;
Snack Link : https://snack.expo.dev/U_fX-6Tao-
I want to make it so when I click a button, the active button backgroundColor should change to "green" and text to "white" and the rest of the buttons backgroundColor and textColor should stay "red". But when I click another button then that button should become active and the previous active button should get back to its normal state.
It would be wonderful if you could also explain the logic behind it as I'm a newbie in React Native.
Thank you.
You are always setting the active button to the first one. Also, I would use an array to render the buttons. I would do something like this:
class App extends Component {
constructor(props){
super(props)
this.state = {
selected: null
}
}
handlePress = (item) => {
this.setState({ selected: item })
}
render() {
return (
<View>
{[...Array(3).keys()].map((item) => {
return (
<TouchableOpacity key={item} style={[styles.Btn, {backgroundColor: this.state.selected === item ? "green" : "white" }]} onPress={() => this.handlePress(item)}>
<Text style={styles.BtnText}>Button {item + 1}</Text>
</TouchableOpacity>
)
})}
</View>
);
}
}
I created an Themed component(OK I did not create it. It is there when I create the app with Expo).
import { useState } from 'react';
import { TouchableOpacity as DefaultTouchableOpacity } from 'react-native';
export type TouchableProps = DefaultTouchableOpacity['props'] & { activeBgColor?: string };
export function TouchableOpacity(props: TouchableProps) {
const [active, setActive] = useState(false);
const { style, activeBgColor, ...otherProps } = props;
if (activeBgColor) {
return (
<DefaultTouchableOpacity
style={[style, active ? { backgroundColor: activeBgColor } : {}]}
activeOpacity={0.8}
onPressIn={() => setActive(true)}
onPressOut={() => setActive(false)}
{...otherProps}
/>
);
}
return <DefaultTouchableOpacity style={style} activeOpacity={0.8} {...otherProps} />;
}
Then I use this TouchableOpacity everywhere.
<TouchableOpacity
style={tw`rounded-sm h-10 px-2 justify-center items-center w-1/5 bg-sky-400`}
activeBgColor={tw.color('bg-sky-600')}
>
<Text style={tw`text-white font-bold`}>a Button</Text>
</TouchableOpacity>
Oh I am writing TailwindCSS with twrnc by the way. You will love it.
See the screenshot below.

How can I keep a check on a radio button in react native?

I'm using a radio button from React Native Paper.
The radio button itself works fine.
But if i move to another page and check the radio button again, the check box cannot be maintained.
How can I keep a check on a radio button?
I am new to React Native.
import React from 'react';
import { StyleSheet, View, TouchableOpacity, Text } from 'react-native';
import { RadioButton } from 'react-native-paper';
import { Actions } from 'react-native-router-flux';
const category = [
{
label: '한식'
},
{
label: '분식'
},
{
label: '카페, 디저트'
}
]
export default class CategoryPage extends React.Component {
constructor(props) {
super(props);
this.state = {
value: ''
}
}
matchingPage() {
Actions.pop();
}
render() {
return (
<View style={styles.container}>
<View style={{ flex: 9, justifyContent: 'center' }}>
<RadioButton.Group onValueChange={value => this.setState({ value })} value={this.state.value}>
{category.map((data, index) =>
<RadioButton.Item
key={index}
style={styles.radioStyle}
label={data.label}
value={data.label}
color='black' />
)}
</RadioButton.Group>
</View>
<View style={{ flex: 1, alignItems: 'center' }}>
<TouchableOpacity
style={styles.buttonStyle}
onPress={this.matchingPage}>
<Text style={styles.buttonTextStyle}>선택 완료</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
import * as React from 'react';
import { View } from 'react-native';
import { RadioButton } from 'react-native-paper';
const MyComponent = () => {
const [checked, setChecked] = React.useState('first');
return (
<View>
<RadioButton
value="first"
status={ checked === 'first' ? 'checked' : 'unchecked' }
onPress={() => setChecked('first')}
/>
<RadioButton
value="second"
status={ checked === 'second' ? 'checked' : 'unchecked' }
onPress={() => setChecked('second')}
/>
</View>
);
};
export default MyComponent;
You can do something like this
Working Example here
import * as React from 'react';
import { View, StyleSheet, TouchableOpacity } from 'react-native';
import { RadioButton, Text } from 'react-native-paper';
const category = [
{
label: '한식',
},
{
label: '분식',
},
{
label: '카페, 디저트',
},
];
const CategoryPage = () => {
const [value, setValue] = React.useState('first');
return (
<View style={styles.container}>
<View style={{ flex: 9, justifyContent: 'center' }}>
<RadioButton.Group
onValueChange={(value) => setValue(value)}
value={value}>
{category.map((data, index) => (
<RadioButton.Item
key={index}
label={data.label}
value={data.label}
color="black"
/>
))}
</RadioButton.Group>
</View>
<View style={{ flex: 1, alignItems: 'center' }}>
<TouchableOpacity
style={styles.buttonStyle}
onPress={this.matchingPage}>
<Text style={styles.buttonTextStyle}>선택 완료</Text>
</TouchableOpacity>
</View>
</View>
);
};
export default CategoryPage;
const styles = StyleSheet.create({});

How to get value of text in state.when i clicked on TouchableOpacity in react-native?

How to get value of text in state.when i clicked on TouchableOpacity in react-native ?
I have gender value in text of TouchableOpacity . so I want to get value of selected gender in state when i clicked on TouchableOpacity.
So please help me how i can achieve this functionality.Thank you in advanced.
This is some part of my screen you can see below.
Create function like this
setGender=(props)={
this.setState({gender:props})
}
call this function from button onPress like this
onPress={()=>this.setGender("Male")}
onPress={()=>this.setGender("Female")
and show state value in Text
Example Codebase :
import React, { Component } from "react";
import {
View,
Text,
StyleSheet,
TextInput,
TouchableOpacity
} from "react-native";
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {
gender: "",
textGender:"Male"
};
}
//Get text value
getTextValue = () => {
alert(this.state.gender);
console.log("Selected Gender is ", this.state.gender);
console.log("Selected Gender From Text ", this.state.textGender);
};
render() {
return (
<View style={styles.container}>
<TextInput
value={this.state.gender}
keyboardType="default"
onChangeText={gender => this.setState({ gender })}
/>
<Text>{this.state.textGender}</Text>
<TouchableOpacity
onPress={() => this.getTextValue()}
></TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
}
});
hope this will help you
onPress = (Male) => {
this.setState({ gender: 'Male'})
}
onPress1 = (Female) => {
this.setState({ gender: 'Female'})
}
<TouchableOpacity
style={styles.button}
onPress={this.onPress(Male)}
>
<Text> Male </Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={this.onPress1(Female)}
>
<Text> Female </Text>
</TouchableOpacity>*
Hope this will help you
import React, { Component } from 'react';
import { View, Text, StyleSheet, Button } from 'react-native';
export default class Home extends Component {
state = {
value: '',
};
onChangeValue = value => {
if (value !== this.state.value) {
this.setState({
value: value,
});
}
};
render() {
return (
<View style={styles.container}>
{this.state.value.length > 0 ? (
<Text
style={{
fontSize: 40,
alignSelf: 'center',
justifyContent: 'center',
}}>
{this.state.value}
</Text>
) : (
<Text
style={{
fontSize: 40,
alignSelf: 'center',
justifyContent: 'center',
}}>
I identify as you
</Text>
)}
<Button
color="#000"
title="Male"
onPress={() => this.onChangeValue('male')}
/>
<Button title="Female" onPress={() => this.onChangeValue('female')} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignContent: 'center',
justifyContent: 'center',
},
});
Feel free for doudts.

Navigating between screens on a TabNavigator with the click of a button in React Native

I have set up a createMaterialTabNavigator with 4 screens. Each of those screens is a React Native component which accepts 3 properties (image, description, and nextPage). 'nextPage' is an onPress function and I am unable to get it to work.
As a workaround I've made separate components (Highlight1, Highlight2, etc.) and an onPress function in each to be able to navigate between them. But that is a lot of repeated code and that is what I want to avoid.
Below is the code for my TabNavigator where I assign each screen the corresponding React component.
routes.js
createMaterialTopTabNavigator(
{
Page1: {
screen: () => (
<Highlight
image={require('../components/Highlights/images/highlight1.png')}
description={'Description 1'}
nextPage={this.props.navigation.navigate('Page2')}
/>
)
},
Page2: {
screen: () => (
<Highlight
image={require('../components/Highlights/images/highlight2.png')}
description={'Description 2'}
nextPage={this.props.navigation.navigate('Page3')}
/>
)
},
Page3: {
screen: () => (
<Highlight
image={require('../components/Highlights/images/highlight3.png')}
description={'Description 3'}
nextPage={this.props.navigation.navigate('Page4')}
/>
)
},
Page4: {
screen: () => (
<Highlight
image={require('../components/Highlights/images/highlight4.png')}
description={'Description 4'}
/>
)
}
},
{
tabBarPosition: 'bottom',
defaultNavigationOptions: {
tabBarVisible: false
}
}
)
Highlight.js
import React, { Component } from 'react';
import { View, Text, Image, ImageBackground } from 'react-native';
import { NextButton } from '../Buttons';
import styles from './styles';
export default class Highlight extends Component {
render() {
return (
<ImageBackground style={styles.container}>
<Image
style={styles.image}
source={this.props.image}
resizeMode="cover"
/>
<View style={styles.textContainer}>
<Text style={styles.text1}>MYAPP</Text>
<Text style={styles.text2}>Highlights</Text>
<Text style={styles.text3}>{this.props.description}</Text>
</View>
<View style={styles.buttonContainer}>
<NextButton onPress={this.props.nextPage} />
</View>
</ImageBackground>
);
}
}
NextButton.js
import React from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
import styles from './styles';
const NextButton = ({ onPress }) => (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<TouchableOpacity style={styles.nextButtonContainer} onPress={onPress}>
<Text style={{ color: 'white', fontSize: 14 }}>NEXT</Text>
</TouchableOpacity>
</View>
);
export default NextButton;
The above spits out the following error -> TypeError: undefined is not an object (evaluating '_this.props.navigation').
How can I get the above to work such that Page1 navigates to Page2, Page2 to Page3, and so on? Additionally, is there a better way to achieve what I am trying to do (which is basically to create a ViewPager consisting of 4 screens)?
The NextButton should be configured as follows:
<NextButton onPress={() => this.props.nextPage} />
const NextButton = (props) => {
const { onPress } = props;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<TouchableOpacity style={styles.nextButtonContainer} onPress={onPress}>
<Text style={{ color: 'white', fontSize: 14 }}>NEXT</Text>
</TouchableOpacity>
</View>
);
};

State does not change until the second button press? Adding a call back throws an error "invariant violation: invalid argument passed"

I'm trying to render a Flatlist that contains a store name. Upon clicking the store name, more information about the store should be displayed.
I attempted to change state and then use
{this.renderMoreDetails(item) && this.state.moreDetailsShown}
to get the additional information to appear. However, it was clear via console.log that state was only changed after a second button press.
From what I read in this article 1 and this article 2 it seemed as though I needed a callback function as an additional parameter to my setState().
I tried adding a callback function(probably incorrect, but I'm extremely lost at this point) and only got more errors.
I know that I have access to all of the data from renderItem inside FlatList. How do I make it appear upon click?
import React, { Component } from 'react';
import {
View,
FlatList,
Text,
TouchableWithoutFeedback,
ListView,
ScrollView
} from 'react-native'
import { NavigationActions } from 'react-navigation';
import { Header, Card, CardSection } from '../common';
import Config from '../Config';
export default class Costco extends Component<Props> {
constructor(props) {
super(props);
this.state = {
stores: [],
selectedItem: {id: null},
};
}
componentWillMount() {
const obj = Config.costcoThree;
const costcoArr = Object.values(obj);
this.setState({
stores: costcoArr,
})
}
renderListOfStores() {
return <FlatList
data={this.state.stores}
renderItem={ ({item}) => this.singleStore(item)}
keyExtractor={(item) => item.id}
extraData={this.state.selectedItem} />
}
singleStore(item) {
console.log(this.state.selectedItem.id)
return item.id === this.state.selectedItem.id ?
<TouchableWithoutFeedback
onPress={() => this.selectStore(item)}
>
<View>
<Text>{item.branchName}</Text>
<Text>Opening Time {item.openingTime}</Text>
<Text>Closing Time {item.closingTime}</Text>
<Text>Address {item.dongAddKor}</Text>
</View>
</TouchableWithoutFeedback>
:
<TouchableWithoutFeedback>
<View>
<Text>{item.branchName}</Text>
<Text>Only showing second part</Text>
</View>
</TouchableWithoutFeedback>
}
selectStore(item) {
this.setState({selectedItem: item});
console.log('repssed');
}
render() {
return(
<ScrollView>
<Header headerText="Costco"/>
<Text>hello</Text>
{this.renderListOfStores()}
</ScrollView>
)
}
}
as a workaround you can have a state that maintain your selected item to expand(or something like another view) and then you can use some conditions to work for render your flat list data.
Consider the below code and let me know if you need some more clarification.
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,FlatList,TouchableNativeFeedback,
View
} from 'react-native';
export default class App extends Component<Props> {
constructor(props) {
super(props);
this.state = {
response: [],
selectedItem: {id: null},
};
}
userListLayout() {
const {response} = this.state;
return <FlatList data={response} renderItem={ ({item}) => this.singleUserLayout(item)} keyExtractor={(item) => item.email} extraData={this.state.selectedItem} />
}
singleUserLayout(item) {
return item.id == this.state.selectedItem.id ?
<TouchableNativeFeedback onPress={() => this.userSelected(item)}>
<View style={{flex:1, borderColor: 'black', borderWidth: 1}}>
<Text style={{padding: 10, fontSize: 25}}>{item.email}</Text>
<Text style={{padding: 10,fontSize: 20}}>{item.name}</Text>
</View>
</TouchableNativeFeedback>
: <TouchableNativeFeedback onPress={() => this.userSelected(item)}><Text style={{padding: 10,fontSize: 20}}>{item.email}</Text></TouchableNativeFeedback>
}
userSelected(item) {
console.log(item)
this.setState({selectedItem: item})
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then(data => data.json())
.then(response => this.setState({response}))
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>HI THERE</Text>
{this.userListLayout()}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});