I am getting this error -
"Objects are not valid as a React child (found: object with keys {$$typeof , type, key, ref, props, _owner, _store}). If you meant to render a collection of children, use an array instead"
This is specifically running the Android Emulator.
Here's my code:
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
userEmail: null
}
//this.authCheck = this.authCheck.bind(this)
//this.toggleLogin = this.toggleLogin.bind(this)
this.signIn = this.signIn.bind(this)
}
componentDidMount() {
this.authListener()
}
authListener() {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log(user.email)
this.setState({userEmail: user.email})
} else {
console.log('no user signed in')
this.setState({userEmail: null})
}
})
}
signIn(email, password) {
//console.log(email, password)
//console.log(this.state.userEmail)
firebase.auth().signInWithEmailAndPassword(email, password)
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode, errorMessage)
// ...
})
}
signUp(email, password) {
firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode, errorMessage)
// ...
})
}
logOut() {
firebase.auth().signOut()
}
render() {
return (
<View style={styles.container}>
{this.state.userEmail ? <ItWorked logOut={this.logOut}/> : <SignUp signIn={this.signIn} signUp={this.signUp} toggleLogin={this.toggleLogin}/>}
</View>
);
}
}
If your code is exactly as you wrote it, then ItWorked and SignUp should be undefined, which would give you an error if you try to use them in the render method.
If you did import those two components, then you might not be importing and exporting them correctly. If this is the case, you might have done something like:
// App.js
// Note that this import expects SignUp to be the default export of SignUp.js
import SignUp from './components/SignUp.js'
export default class App extends Component {
...
// SignUp.js
// Note that this is a named export of SignUp
export function SignUp() {
return <div>Lorem Ipsum</div>
}
To solve this, either export SignUp as the default:
// SignUp.js
export default function SignUp() {
return <div>Lorem Ipsum</div>
}
OR import SignUp as a named import:
// App.js
import { SignUp } from './components/SignUp.js'
...
But not both.
Another possible issue is that the rendered components (
ItWorked and SignUp) are wrapped in higher order components (like react-redux's connect), but the exporting file does not actually call the HOC.
I suspect you might find that one (or both) of those files does something like this:
// SignUp.js
function SignUp(props) {
return <div>Lorum Ipsum</div>
}
// Possible current export
export default connect(mapStateToProps)
// "Correct" export
export default connect(mapStateToProps)(SignUp)
Either way, the problem probably lies in the SignUp and ItWorks components or how they are imported by App, and it would help to get a bit more context into those components.
Related
Im working on my first Ionic + Firebase project, and im not understanding this:
Im searching and getting an object from firebase, I can access its details on html and show it to the user.
But now I need to save the createdBy field on that object so I can use it to search for its creator on firebase.
But when I try to access that info its always undefined. Why is that? Any tips on how to fix this?
export class VisitDetailsPage implements OnInit {
public trips: Observable<HomeTripCardsModel>;
public trip: HomeTripCardsModel;
public buddyInfo;
public targetBuddyId: any;
constructor(private router: Router, private navCtrl: NavController,
public fireStorageService: FireStorageService,
private route: ActivatedRoute, public db: AngularFirestore) {
}
ngOnInit() {
const tripId: string = this.route.snapshot.paramMap.get('id');
this.db.collection('users').get()
.subscribe(querySnapshot => {
querySnapshot.forEach(doc => {
this.trips = this.fireStorageService.getTripDetail(tripId, doc.id);
this.trips.forEach((element: HomeTripCardsModel) => {
if (element?.id === tripId) {
this.trip = element;
this.targetBuddyId = element.createdBy;
}
});
});
});
// buddy
console.log(this.trip?.createdBy); // returns undefined
console.log('saved ', this.targetBuddyId) // returns undefined
}}
Data is loaded from Firebase asynchronously. If you set some breakpoints and run in the debugger, or add a log inside the subscribe method, you'll see that your console.log(this.trip?.createdBy) runs before this.trip = element has ever been run. So at that point, it indeed doesn't have a value yet.
For this reason, all code that needs data from the database, needs ot be inside the subscribe callback:
this.db.collection('users').get()
.subscribe(querySnapshot => {
querySnapshot.forEach(doc => {
this.trips = this.fireStorageService.getTripDetail(tripId, doc.id);
this.trips.forEach((element: HomeTripCardsModel) => {
if (element?.id === tripId) {
this.trip = element;
this.targetBuddyId = element.createdBy;
}
});
// buddy
console.log(this.trip?.createdBy); // returns undefined
console.log('saved ', this.targetBuddyId) // returns undefined
});
});
I got this problem when i expo publish my react native app with or without --release-channel dev flag.
I set up a config file environment.js to get different release version like this :
import Constants from "expo-constants";
import { Platform } from "react-native";
const localhost = Platform.OS === "ios" ? "localhost:8080" : "10.0.2.2:8080";
const ENV = {
localhost: {
//apiUrl: localhost,
apiUrl: "http:xxxx",
},
dev: {
apiUrl: "http:xxxx",
},
staging: {
apiUrl: "http:xxxx",
// Add other keys you want here
},
prod: {
apiUrl: "http:xxxx",
// Add other keys you want here
},
};
const getEnvVars = (env = Constants.manifest.releaseChannel) => {
// What is __DEV__ ?
// This variable is set to true when react-native is running in Dev mode.
// __DEV__ is true when run locally, but false when published.
if (__DEV__ || env === undefined || env === null || env === "") {
return ENV.localhost;
} else if (env.indexOf("dev") !== -1) {
return ENV.dev;
} else if (env.indexOf("staging") !== -1) {
return ENV.staging;
} else if (env.indexOf("prod") !== -1) {
return ENV.prod;
}
};
export default getEnvVars;
I intercept the config with creation of new intance of axios like this :
import axios from "axios";
import { getKey } from "./deviceStorage";
import getEnvVars from "../../environment";
const { apiUrl } = getEnvVars();
const instance = axios.create({
// .. where we make our configurations
baseURL: apiUrl,
});
instance.interceptors.request.use((config) => {
const token = getKey("id_token");
token.then((value) => {
config.headers.Authorization = value ? `Bearer ${value}` : "";
});
return config;
});
export default instance;
when i emulate on my device everything work fine but when i expo publish and scan QR code with my device the app crash after splash screen and i got this error say :
So if i understand well the Constants.manifest.releaseChannel is undefined, any idea why this happen ? do i miss somthing on the import ?
When i put the Api URL directly on my axios interceptors everything work fine.
import axios from "axios";
import { getKey } from "./deviceStorage";
//import getEnvVars from "../../environment";
//const { apiUrl } = getEnvVars();
const instance = axios.create({
// .. where we make our configurations
baseURL: "http://xxxx",
});
instance.interceptors.request.use((config) => {
const token = getKey("id_token");
token.then((value) => {
config.headers.Authorization = value ? `Bearer ${value}` : "";
});
return config;
});
export default instance;
export const ApiUrls = {
authPatient: "/xxx",
authPractician: "/xxx",
};
Thanks for help.
I find my problem here and maybe will help anyone on the future so :
i delete the env parameter on the getEnvVars and i declared inside the function and everything work fine :
const getEnvVars = () => {
const env = Constants.manifest.releaseChannel;
if (!__DEV__ && env) {
switch (env) {
case env.indexOf("dev") !== -1:
return ENV.dev;
case env.indexOf("staging") !== -1:
return ENV.staging;
case env.indexOf("prod") !== -1:
return ENV.prod;
default:
return ENV.localhost;
}
}
return ENV.localhost;
};
Moving the declaration of env into the function didn't work for me so I cut out the function altogether and that fixed my issue up. Going to have to figure out a way to rewrite it. But thank you for posting this anyways
I'm dynamically creating components in create-react-native-app. Everything is working fine using the expo app for testing in Development mode using npm start, and connecting with an android phone.
If I switch it to Production mode, or try to build the apk as a Standalone app the object is not created on the Button press.
This is my first project with React Native, and I don't know how to debug this.
I've also been unable to find any information about what the differences between these two modes might be that would lead to this.
Here the relevant code:
export default class App extends React.Component {
constructor(props) {
super(props);
this.updateState = this.updateState.bind(this);
this.state = {
knobs: [],
key: 1
}
}
add = () => {
let key = this.state.key + 1
let knob = (<Object key={key} updateState={this.updateState}/>);
let knobs = this.state.knobs;
knobs.push(knob);
this.setState({knobs: knobs, key: key})
}
render = () => {
return ([<View>
{this.state.knobs}
<Button onPress={() => this.add()} title='add thing'/>
</View>
]);
}
}
I'm not sure what causes the issue since we don't have any sort of error message but below snippet of code might help.
When you assign a variable like below;
let knobs = this.state.knobs;
You are not creating a new variable, you are creating a reference to the original property. Because of this you mutate the state. This might cause the issue.
For setting new state values related to current state values you can use functional setState syntax and destructuring assignment. It is a little bit more easy to use and a little bit more easy to read.
add = () => {
this.setState((prevState) => {
const { knobs, key } = prevState; // deconstruct array and key from state
const newKnob = (<Object key={(key + 1)} updateState={this.updateState}/>);
knobs.push(newKnob); // push new item to array
return { knobs, key: (key + 1) } //return new state values
});
}
Oh, so in the end I rewrote the whole bit.
Moving the objects to be created into the render function.
export default class App extends React.Component {
constructor() {
super();
this.state = {
things: []
}
this.key = 0;
}
add = () => {
let addThing = { key: this.key }
this.setState({ things: [ ...this.state.things, addThing ] })
this.key = this.key + 1;
}
render() {
let newThings = this.state.things.map((key) => {
return (
<Text key={key}>New Thing.</Text>
);
});
return (<View style={styles.container}>
{newThings}
<Button onPress={() => this.add()} title='add thing'/>
</View>);
}
}
This functions as expected in Production mode and as an App;)
i am using React Native Share Method (https://facebook.github.io/react-native/docs/share.html) to share content on Android.
As per documentation, we can use it in following ways:
Share.share({
message: 'React Native | A framework for building native apps using React'
})
.then((result) => {
console.log(result.action) // returns sharedAction
})
.catch((error) => {
console.log(error)
})
So when we call Share method, we will get result in then and popup window is appeared which contains apps list with which we can share the message content.
Issue:
Popup window also contains a cancel button, so when user click on it, window get closed, but there is no method available/mentioned to capture it, in docs.
Is there any way to capture the cancel event, as i want to perform some action when user clicks on it.
Thanks in adv. :)
There is option in share dismissedAction but unfortunately this is IOS only . You can use react-native-share with prop "failOnCancel" to true and it will work on both android and ios
Sample Code
import React, { Component } from "react";
import { Button } from "react-native";
import Share from "react-native-share";
export default class ShareExample extends Component {
onShare = async () => {
const shareOptions = {
title: "Share file",
social: Share.Social.EMAIL,
failOnCancel: true
};
try {
const ShareResponse = await Share.open(shareOptions);
//setResult(JSON.stringify(ShareResponse, null, 2));
} catch (error) {
console.log("Error =>", error);
}
};
render() {
return <Button onPress={this.onShare} title="Share" />;
}
}
App Preview
This might help
import React, {Component} from 'react';
import {Share, Button} from 'react-native';
class ShareExample extends Component {
onShare = async () => {
try {
const result = await Share.share({
message:
'React Native | A framework for building native apps using React',
});
if (result.action === Share.sharedAction) {
if (result.activityType) {
// shared with activity type of result.activityType
} else {
// shared
}
} else if (result.action === Share.dismissedAction) {
// dismissed
}
} catch (error) {
alert(error.message);
}
};
render() {
return <Button onPress={this.onShare} title="Share" />;
}
}
I have a strange error on my react-native Firebase APL.
react-native run-android works fine without error.
but react-native run-ios failed with JSON value of type NSnull cannot be converted to NSString.
source code is as follows.(main and signup class to authentication work on firebase)
I think Firebase Class has different ACT on ios and Android to convert JSON to text.
Any suggestion appreciated.
Shoji
main
// Initialize the firebase app here and pass it to other components as needed. Only initialize on startup.
const firebaseApp = firebase.initializeApp(firebaseConfig);
var GiftedMessenger = require('react-native-gifted-messenger');
let styles = {}
class Pricing extends Component {
constructor(props){
super(props);
this.state = {
page: null
};
/* this.itemsRef = this.getRef().child('items'); */
}
componentWillMount(){
// We must asynchronously get the auth state, if we use currentUser here, it'll be null
const unsubscribe = firebaseApp.auth().onAuthStateChanged((user) => {
// If the user is logged in take them to the accounts screen
if (user != null) {
this.setState({page: Account});
console.log('(user != null)')
return;
}
// otherwise have them login
console.log('(user != Login)')
this.setState({page: Login});
// unsubscribe this observer
unsubscribe();
});
}
render() {
if (this.state.page) {
return (
// Take the user to whatever page we set the state to.
// We will use a transition where the new page will slide in from the right.
<Navigator
initialRoute={{component: this.state.page}}
configureScene={() => {
return Navigator.SceneConfigs.FloatFromRight;
}}
renderScene={(route, navigator) => {
if(route.component){
// Pass the navigator the the page so it can navigate as well.
// Pass firebaseApp so it can make calls to firebase.
return React.createElement(route.component, { navigator, firebaseApp});
}
}} />
);
} else {
return (
// Our default loading view while waiting to hear back from firebase
I deeply debug in this BUG.
At last I found it as follows.
<Image
source={{uri: 'this.state.user.photoURL'}} <<<single quotation was added.
style={styles.image}
/>
I did not expect like this kind of error.
Thanks Shoji
took help from #itagaki. Error was removed after replacing single quote with double quote in following code
const BoldText = (props) => <Text style={{fontWeight: 'bold'}}>{props.children}</Text>;