This question already has answers here:
Firebase data not defined when used inside react useState
(2 answers)
Initiate React components with data from Firebase database?
(1 answer)
Closed 1 year ago.
I used the blow code to get data from the firebase:
import firebase from 'firebase';
import 'firebase/database'
firebase.database().ref().child('users').on('value',(snapshot)=>{
if(snapshot.exists()){
snapshot.forEach((datasnapshot)=>{
data.push({key: datasnapshot.key.toString()})
})
} else {
data.push({key: 'No one has written yet'})
}
});
var data = [];
export default data;
Later i tried to import the variable data to display it as below:
import React from 'react';
import {StyleSheet, Text, StatusBar, View, TouchableOpacity, ScrollView } from 'react-native';
import firebase from 'firebase';
import 'firebase/database'
import data from './getdata';
export default function Index({navigation}) {
return (
<View style={styles.container}>
<Text style={{color: '#000000', fontSize: 30, fontWeight: 'bold', marginTop: StatusBar.currentHeight}}>Index</Text>
<ScrollView>
{data.map((item,key)=>{
if(item.key == "No one has written yet"){return(<Text key={key} style={styles.item}>{item.key}</Text>)}
else{
return(
<TouchableOpacity key={key} onPress={()=>navigation.navigate('Details',item.key)}>
<Text style={styles.item}>{item.key}</Text>
</TouchableOpacity>
)
}
})}
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
item: {
marginTop: 10,
fontSize: 20,
fontWeight: 'bold',
color: '#000000',
textAlign: 'center'
}
});
the problem is it does not show the data stored after the 'data' array is updated by 'push()' function until i save it once again and the code is refreshed in 'expo go' app.
Here is the image of how it is displayed at first when the app is opened:
Click for the image
I think the problem is that your component is not re-rendering after getting data thus the new data is not shown.
I would use Flatlist as it has extraData prop that will make Flatlist re-render when data set to it changes:
"By passing extraData={selected} to FlatList we make sure FlatList itself will re-render when the state changes. Without setting this prop, FlatList would not know it needs to re-render any items because it is a PureComponent and the prop comparison will not show any changes."
https://docs.expo.dev/versions/latest/react-native/flatlist/
So changing your SrollView to...
<FlatList
data={data}
extraData={data}
renderItem={({ item, key }) => {
if(item.key == "No one has written yet"){
return(<Text key={key} style={styles.item}>{item.key}</Text>)
}else{
return(
<TouchableOpacity key={key} onPress={()=>navigation.navigate('Details',item.key)}>
<Text style={styles.item}>{item.key}</Text>
</TouchableOpacity>
)
}}
/>
Related
I get this error while trying to navigate between screens with react native stack navigator. I think this was working in my previous project which had react 17.0.1 and react native 0.64.2, this project is react 17.0.2 and react native 0.66.4, helps would be appreciated.
log
Warning: Cannot update a component (`ForwardRef(BaseNavigationContainer)`) while rendering a different component (`Home_Profile`). To locate the bad setState() call inside `Home_Profile`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
error comes when I try to call navigation in an onPress prop on a Flatlist render item component.
renderItem={({ item }) => (
<View style={{ backgroundColor: "#f6f6f6" }}>
<PostCard
item={item}
onPress={() => navigation.navigate("Home_Profile")}
/>
</View>
)}
const PostCard = ({ item, onPress }) => {
React.useEffect(() => {
async function fetchUserData() {
const data = await getUserData(item.userid);
setProfileimg(data.userimg);
setName(data.name);
setLocation(data.location);
}
fetchUserData();
}, []);
return (
<TouchableOpacity onPress={onPress}>
<Text
style={{
color: "#231454",
fontWeight: "bold",
fontSize: 15,
marginBottom: 3,
}}
>
{name}
</Text>
</TouchableOpacity>
)
};
export default PostCard;
Home_Profile
import React from "react";
import { View, Text, Button } from "react-native";
const Home_Profile = ({ navigation }) => {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Home_Profile.js</Text>
<Button title="back" onPress={navigation.navigate("Home")} />
</View>
);
};
export default Home_Profile;
I found the cause of the problem, when you render the second screen, it is executing the onPress method of the button that goes back home, and that navigation causes the render method in that home screen to execute, which means you are trying to execute two renders at the same time, to fix that, just add an arrow function to the navigate home function as shown bellow:
onPress={()=>{navigation.navigate("Home")}}
You have forgot to add an arrow function before navigation.navigation('nameOFComponent')
I am using JavaScript + React Native to make an app for my university project. I am using expo to manage my packaging and for viewing the app in the iOS simulator. I am also new to both JavaScript and React Native.
I have been having trouble with implementing a React Native module known as Secure Storage.
https://docs.expo.io/versions/latest/sdk/securestore/
I would like to store user data for the app. Specifically I would like to store a JavaScript object such as:
User{ name:"Bob", age:"20" }
And recall it later.
Having read the documentation, I have made a helper module called "StorageHelper" as seen below:
import * as SecureStore from 'expo-secure-store';
/**
* Stores data
* #param {} key
* #param {*} value
*/
export async function storeObject(key, value)
{
try
{
const jsonValue = JSON.stringify(value);
await SecureStore.setItemAsync(key, jsonValue);
}
catch(e)
{
console.log(e.message);
}
}
/**
* Retrieves data
* #param {} key
*/
export async function getObject(key)
{
let result = await SecureStore.getItemAsync(key);
if (result != null)
{
return result;
}
else
{
alert('No values stored under that key.');
}
On this screen in the app flow, I would like to generate the userObject object and store it in the SecureStorage. This following is
import React from 'react';
import { Text, View, TouchableOpacity, Image } from 'react-native';
import ProjStyleSheet from "../styles/ProjStyleSheet.js";
import * as StorageHelper from "../resources/StorageHelper.js";
const HomeImage = require('../art/HomeImage.png');
const styles = ProjStyleSheet;
function HomeScreen({ navigation }) {
var userData = "Bob"; // instead of the object, I'm just using a simple variable.
StorageHelper.storeObject("userName",userData);
return (
<View style={{
backgroundColor: "#fff",
flexDirection: "column",
justifyContent: "flex-start",
flex:1,}}>
<View style = {{
paddingTop: 100,
paddingBottom: 20,
paddingLeft: 10,
paddingRight: 10,
}}>
<Text style={styles.titleText}>University Money Management App</Text>
</View>
<View style = {{
justifyContent: "space-evenly",
alignItems: "center",
}}>
<Image
style={{width: 250, height: 250, paddingBottom:20}}
source={HomeImage}/>
<TouchableOpacity style={styles.defaultButton}
onPress={() => navigation.navigate('IntroName')}>
<Text style={styles.text}> Get Started </Text>
</TouchableOpacity>
</View>
</View>
);
}
export default HomeScreen;
In the next screen, I am trying to get the data from the secure storage and show it on the screen. This can be seen below:
import React, { useState } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import ProjStyleSheet from "../styles/ProjStyleSheet.js";
import { TextInput } from 'react-native-gesture-handler';
import * as StorageHelper from "../resources/StorageHelper.js";
const styles = ProjStyleSheet;
function IntroName({ navigation })
{
var name = StorageHelper.getObject("userName"); // retrieve the variable here.
return (
<View style={{
flex: 1,
backgroundColor: "#fff",
alignItems: 'center',
justifyContent: "space-around",}}>
<Text style={styles.titleText}>Please Enter Your Name</Text>
<Text> test = {name} </Text> // show the name here
<TextInput
style={{
borderColor: "#000",
borderRadius: 10,
borderWidth: 2,
padding: 20,
fontSize: 20,
width: "75%",
}}
placeholder="Your name here.">
</TextInput>
<TouchableOpacity
style={styles.defaultButton}
onPress={() => navigation.navigate("IntroIncome")}>
<Text style={styles.text}>Next</Text>
</TouchableOpacity>
</View>
);
}
export default IntroName;
Unfortunately, no name appears in the text where I intend it to. I have gone through the Secure Storage documentation and searched through the internet, however I cannot find any answers that can help me. Does anyone have any good ideas on what I am missing to fully implement SecureStorage?
the solution is quite simple. Thanks to the advice of #Tony, I converted all my function components to class components. Within those class components, I wrote an async method which calls the SecureStore method as such: await SecureStore.setItemAsync("user",this.name).
The async method updates the state of the screen, i.e
class Scren extends React.Component
{
constructor()
{
super();
this.state={
data:0,
};
}
async getObject()
{
let result = JSON.parse(await SecureStore.getItemAsync("data");
this.setState({
data: result,
};
}
}
I'm trying to create a simple-ish mobile app, but I'm pretty new to this. I've spent some time searching about the errors I'm getting. It seems like a common problem, but they all had the same/similar solutions but the solutions didn't work for me.
What is I'm trying to do? Right now the app is two pages, the home screen (Overview Cards) and the Add Card screen.
There's a button on the Overview Cards that takes you to Add Card.
Add Card allows you to fill out some TextInput boxes and
Add Card should allow you to press the save button and be taken back to the Overview Card screen and see the data you entered in the form.
However, I am getting stuck at Step 3. I am trying to make the Save button navigate the user back to Overview Cards, but there are simply errors instead.
Below is my code, the errors I'm getting, and then what I've tried.
App.js
import React from 'react';
import { StyleSheet, Text, TextInput, View, Button, TouchableOpacity, ShadowPropTypesIOS } from 'react-native';
import AddCard from './components/AddCard.js';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { useNavigation } from '#react-navigation/native';
function HomeScreen({ navigation }) {
return (
<View style={styles.homeContainer}>
<Button title="Add Card" onPress={() => navigation.navigate('Add Card')}/>
{/* <Text value={this.props.inputValFT}/> */}
<Text style={styles.textStyle} >VISA xxxx</Text>
<Text style={styles.textStyle}>MASTERCARD xxxx</Text>
<Text style={styles.textStyle}>AMEX xxxx</Text>
</View>
);
}
function AddCardScreen() {
return (
<View style={styles.addCardContainer}>
<AddCard navigation={this.props.navigation} /> // **HERE**
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Overview Cards' }} />
<Stack.Screen name="Add Card" component={AddCardScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
// function AddCardButton(){
// return (
// <View style={styles.buttonContainer}>
// <TouchableOpacity>
// <Text style={styles.button}>Add Card</Text>
// </TouchableOpacity>
// </View>
// );
// }
export default App;
const styles = StyleSheet.create({
homeContainer: {
flex: 1,
backgroundColor: '#ef95b1',
alignItems: 'center',
justifyContent: 'flex-start',
},
addCardContainer: {
flex: 1,
backgroundColor: '#28cdf0',
justifyContent: 'flex-start',
},
buttonContainer: {
flexDirection: 'row',
alignSelf: 'flex-end',
marginTop: 15,
},
button: {
flexDirection: 'row',
alignSelf: 'flex-end',
marginTop: 15,
right: 10,
backgroundColor: '#2565ae',
borderWidth: 1,
borderRadius: 12,
color: 'white',
fontSize: 15,
fontWeight: 'bold',
overflow: 'hidden',
padding: 10,
textAlign:'center',
},
textStyle: {
padding: 10,
}
});
Navigation.js
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import AddCardScreen from './AddCard';
const RootStack = createStackNavigator(
{
Home: HomeScreen,
AddCard: AddCardScreen,
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ef95b1',
alignItems: 'center',
justifyContent: 'flex-start',
},
textStyle: {
padding: 10,
}
});
export default createAppContainer(Navigation);
AddCard.js
import React, { Component } from 'react';
import { StyleSheet, View, Text, TextInput, TouchableOpacity } from 'react-native';
import { Input } from 'react-native-elements'
import { ScrollView } from 'react-native-gesture-handler';
// import { loadSettings, saveSettings } from '../storage/settingsStorage';
class AddCardScreen extends Component {
constructor(props) {
super(props);
this.state = {
firstTwo : '',
lastFour : '',
recentAmt : ''
};
this.addFT = this.addFT.bind(this)
this.addLF = this.addLF.bind(this)
this.addRecAmt = this.addRecAmt.bind(this)
}
static navigationOptions = {
title: 'Add Card'
};
addFT(firstTwo) {
this.setState(Object.assign({}, this.state.firstTwo, { firstTwo }));
}
addLF(lastFour) {
this.setState(Object.assign({}, this.state.lastFour, { lastFour }));
}
addRecAmt(recentAmt) {
this.setState(Object.assign({}, this.state.recentAmt, { recentAmt }));
}
// handleSubmit() {
// alert('New card saved. Returning to Home to view addition.');
// navigation.navigate('Home')
// } // firstTwo, lastFour, recentAmt
render() {
const {navigation} = this.props;
return (
<ScrollView>
<View style={styles.inputContainer}>
<Text h1> "Add a new card!" </Text>
<TextInput
style={styles.textInput}
placeholder="First two digits of card"
placeholderTextColor="#000000"
keyboardType={'number-pad'}
maxLength = {2}
onChangeText={this.addFT}
inputValFT={this.state.firstTwo}
/>
<TextInput
style={styles.textInput}
placeholder="Last four digits of card"
placeholderTextColor="#000000"
keyboardType={'number-pad'}
maxLength = {4}
onChangeText={this.addLF}
inputValLF={this.state.lastFour}
/>
<TextInput
style={styles.textInput}
placeholder="Most recent dollar amount"
placeholderTextColor="#000000"
keyboardType={'decimal-pad'}
onChangeText={this.addRecAmt}
inputValRA={this.state.recentAmt}
/>
</View>
<View style={styles.inputContainer}>
<TouchableOpacity
style={styles.saveButton}
onPress={() => navigation.navigate('Home')}> // ** HERE 2 **
<Text style={styles.saveButtonText}>Save</Text>
</TouchableOpacity>
</View>
</ScrollView>
);
}
}
// this.handleSubmit.bind(this)
export default AddCardScreen;
const styles = StyleSheet.create({
inputContainer: {
paddingTop: 15
},
textInput: {
borderColor: '#FFFFFF',
textAlign: 'center',
borderTopWidth: 1,
borderBottomWidth: 1,
height: 50,
fontSize: 17,
paddingLeft: 20,
paddingRight: 20
},
saveButton: {
borderWidth: 1,
borderColor: '#007BFF',
backgroundColor: '#007BFF',
padding: 15,
margin: 5
},
saveButtonText: {
color: '#FFFFFF',
fontSize: 20,
textAlign: 'center'
}
});
The errors I'm getting:
In App.js you can see the ** HERE ** that I put in. When I try to run this, the app loads fine until I click the "Add Card" button. I get this error: undefined is not an object (evaluating 'this.props.navigation').
If I take the navigate={this.props.navigation} part out from App.js, the app loads as it's meant to again, but this time I can click the "Add Card" button and reach the next screen with no issue. I fill out the form (TextInput parts in AddCard.js), but when I click the "Save" button, the app crashes. The error is: TypeError: undefined is not an object (evaluating 'navigation.navigate'). Most likely because of what I'm doing with onPress where it says ** HERE 2 ** in AddCard.js. handleSubmit() is currently commented out, but it used to be inside the onPress.
What I've tried:
Some of the answers I saw were that I need to pass in navigation from the parent to the child and that will make it work. By trying that, I get the errors I mentioned earlier. I also saw that someone mentioned using "withNavigation" or "useNavigation" which was supposed to allow the child to access navigation, but that didn't work for me either. Below are some of the links that I was trying to follow.
How do I pass navigation props from parent component to header?
Pass navigation.navigate to Child Component
https://reactnavigation.org/docs/use-navigation/
Thank you for reading, hopefully my explanation is clear enough.
I think your problem is somewhere here:
function AddCardScreen({ navigation }) {
return (
<View style={styles.addCardContainer}>
<AddCard navigation={navigation} />
</View>
);
}
There is no this, you're not in a class component, therefore this doesn't exists
The prop you are trying to pass should be called navigation and not navigate, since that's how you try to access it in the child component.
The navigation prop needs to be destructured inside the function argument function AddCardScreen({ navigation }), same as you already do for HomeScreen.
I'm learning to programming in React-Native (and also in Javascript) and I have a question.
Basically, I have created a Login for 2 categories of users: "Regular" and "Plus".
After the login they are redirect to an HomeUser page.
My problem is that in this "HomeUser" page I should create dynamic Content depending on the type of user.
This is the HomeUser
class HomeUser extends Component {
constructor(props){
super(props);
}
render() {
const FirstName = global.utente.data.Person.FirstName;
const LastName = global.utente.data.Person.LastName;
const Username = global.utente.data.Person.FiscalCode;
const Roles = global.utente.data.Roles
console.log(Roles)
return (
<View style={style.container}>
<View style={style.page}>
<Icon name="user-circle" color="#64c7c0" size={70} onPress={() => Actions.viewprofile()} />
<Text style={{paddingBottom: 15, textAlign: 'center', fontSize: 15, color: '#64c7c0', fontWeight: 'bold'}}>View Profile</Text>
<Text style={{textAlign: 'center', fontSize: 20,}}>{"Welcome"}</Text>
<Text style={{textAlign: 'center', fontSize: 20, color: '#64c7c0', fontWeight: 'bold'}}>{FirstName} {LastName}</Text>
<Text>{Roles}</Text>
//Add here "EDIT PROFILE" button to link a the page to edit profile, only for Regular User.
</View>
</View>
)
}
}
export default HomeUser;
So I should insert content dynamically for the users. Can you explain how can I do for example to the edit profile? I should create a new page and link to this page with a If condition? ( I don't think so xD )
My thought is that if I have to do more checks on the role, the efficiency of the application slows down. Is it possible that this problem occurs?
If i understand your question correctly you want to render a component when the user role is a specific one.
In this case you can use conditional rendering using:
{condition && <Component>}
inside you render return function.
In your code something like:
{Roles==="SpecificRole"&&<Button></Button>}
should do the trick
First Edit profile when you login success you can save user fix information on local storage then you can open new page name UserEditProfile it's a good way for efficiency.
If wanna show 1 page 2 different role stuff component you must create 2 component like that
//it's different .jsx file
<RegularUserComponent /*you can add props here*/ />
<SpecificRoleUserComponent />
then you can call like that
import RegularUserComponent from './components/RegularUserComponent.js'
import SpecificRoleUserComponent from './components/RegularUserComponent.js';
and use like that
// in render
{Roles==="Reqular" ? <RegularUserComponent/> :<SpecificRoleUserComponent/> }
localstorage about the information you must check this link
and An Example for a compornt
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View,Button,Image} from 'react-native';
export default class NameOfYouComponent extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
const {RequestResponse} = this.state;
return (
<View style={styles.container}>
{/*Here is Component include*/}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
});
you can call like that
import NameOfYouComponent from './../afolder/Component/NameOfYouComponent'
Here is the sample code , i am trying react-native-navigation
i used react-native init navigate to start the project
and afterwards i installed
yarn add react-native-navigation#latest
the code run perfect for first screen , but as i am making a call to showNextScreen function it throws the error
undefined is not an object (evaluating 'this.props.navigator.push') react native
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import {Navigation} from 'react-native-navigation';
import firstPage from './app/components/firstPage';
export default class navigate extends Component {
//function to move to next screen
showNextScreen = () =>{
this.props.navigator.push({
screen: 'firstPage',
title: 'firstScreen'
})
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text onPress={this.showNextScreen.bind(this)}
style={styles.instructions}>
Double tap R on your keyboard to reload,{'\n'}
Shake or press menu button for dev menu
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('navigate', () => navigate);
Using React Native Navigation, you have to bootstrap your app differently than how it's done originally. Native Navigation doesn't use the registerComponent setup since it's a native navigator.
The steps to fully setting up are listed in their docs https://wix.github.io/react-native-navigation/#/usage