I can't seem to get createContainer to work with React Native and Meteor data. I'm currently using the react-native-meteor package and the latest releases of Meteor/React Native. I've reviewed the info for the package and Meteor's official write-up of createContainer. I guess first off, I'm not really sure how this container works. It looks like it wraps the component called at the end and updates it when the reactive data changes?
I've tried it a few different ways but below is what I currently am using. I'm not sure if createContainer is even getting called, as I don't see anything in the console from my log statement. I've tried using Meter.user() and Meteor.userId() as well with no luck. Any idea as to what I'm doing wrong?
'use strict';
import React, { Component } from 'react'
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import { loginToSpotify } from './react-native-spotify-auth'
import Meteor, { createContainer } from 'react-native-meteor'
//import { testComponent } from './component'
//TODO: openURL bug on iOS9 causes iOS to confirm before redirect: http://stackoverflow.com/questions/32312009/how-to-avoid-wants-to-open-dialog-triggered-by-openurl-in-ios-9-0
//May also want to look into using Universal links
Meteor.connect('http://localhost:3000/websocket');//do this only once
class ReactNativeApp extends Component {
constructor(props) {
super(props);
this.state = {
access_token: null
};
}
componentDidMount() {
loginToSpotify();
}
render() {
const { todosReady } = this.props;
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.ios.js
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
<Text>
Hello {!todosReady && <Text>Not Ready</Text>}
</Text>
</View>
);
}
}
export default createContainer(params=>{
const handle = Meteor.subscribe('todos');
console.log('todos: ' + Meteor.collection('todos').find());
return {
todosReady: handle.ready()
}
}, ReactNativeApp);
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('ReactNativeApp', () => ReactNativeApp);
Can you see in console that meteor connected to the app? You shouldn't use http in Meteor.connect anymore, instead ws://localhost:3000/websocket
Be sure that your meteor application is running.
Use the IP of your local machine, don't use localhost. If you are using mobile as emulator that's good. Connect both in Router and use your machine language.
For more information you can follow this React Native Meteor Boilerplate.
Related
I am using global object to store font names (so later I can change all the fonts), but some how they not applied unless I save the component (and trigger hot-reload).
After experiments I found that global do not store values in the beginning, so the hot reload have to re-assign values to global variables that closured.
Code:
App.jsx
...
global.fontRegular = 'Montserrat-Regular';
global.fontSemiBold = 'Montserrat-SemiBold';
global.fontExtraBold = 'Montserrat-ExtraBold';
...
HeaderTitle.jsx
import React from 'react';
import {Text, TouchableOpacity, StyleSheet} from 'react-native';
const styles = StyleSheet.create({
text: {
fontSize: 24,
color: '#f1f1f1',
textAlign: 'center',
fontFamily: global.fontExtraBold,
margin: 10,
},
});
export default function () {
return (
<TouchableOpacity>
<Text style={styles.text}>SUPPORT.UA</Text>
</TouchableOpacity>
);
}
Screen before hot-reload
Screen after hot-reload
What I found out, is that using global object do not work for enclosured object if not in export body, so original code WILL NOT WORK,
but the following one WILL (now I wonder how this works):
import React from 'react';
import {Text, TouchableOpacity, StyleSheet} from 'react-native';
export default React.memo(function ({navigation, ...props}) {
const styles = StyleSheet.create({
text: {
fontSize: 24,
color: '#f1f1f1',
textAlign: 'center',
fontFamily: global.fontExtraBold,
margin: 10,
},
});
return (
<TouchableOpacity onPress={() => navigation.navigate('MainScreen')}>
<Text style={styles.text}>SUPPORT.UA</Text>
</TouchableOpacity>
);
});
Your const styles object is declared outside a function block, therefore it is evaluated immediately on app launch (with global.yourFont being unassigned yet). However, assignments to global are operations, that are done after the entire code has been crawled and unscoped const's have been evaluated. Therefore, moving it inside a component fixes the problem, because the component function will be called way after the initial crawl.
I am using laravel as my back-end and I've tested all the method and it works tho. I already test it using postman for my laravel as a backend and it works. But when I try it in react native it didnt work at all. I'm still new to react native.
Here's my code for PinjamList.js in RN:
import React, {Component} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import PropTypes from 'prop-types';
export default class PinjamList extends Component {
static propTypes = {
pinjams: PropTypes.array.isRequired
};
render() {
return ({
this.props.pinjams.map((pinjam) => {
return ({pinjam.ketua_kegiatan} | {pinjam.lab})
})
});
}
}
const styles = StyleSheet.create({
pinjamList: {
flex: 1,
flexDirection: 'column',
justifyContent: 'space-around',
},
pinjamtext: {
fontSize: 24,
fontWeight: 'bold',
textAlign: 'center',
}
});
And this one is js file for fetching the data:
const URI = 'http://localhost:8000';
export default {
async fetchDataPinjam() {
try {
let response = await fetch(URI + '/api/pinjams');
let responseJsonData = await response.json();
return
responseJsonData;
} catch (e) {
console.log(e);
}
}
}
And this one is the code for displaying the data on the homepage:
<View> { this.state.pinjams.length > 0
? <PinjamList pinjams={this.state.pinjams} />
: <Text>Tidak Ada Peminjaman</Text> } </View>
But when I try to test it to make sure if its right, this error shown:
Network request failed
- node_modules\react-native\Libraries\vendor\core\whatwg-fetch.js:504:29 in onerror
- node_modules\event-target-shim\lib\event-target.js:172:43 in dispatchEvent
- ... 8 more stack frames from framework internals
First thing : the API what is the HTTP method ?
Second thing : if the method is get please add screen shot about results from your browser or postman
Anyway, It's Fixed already,,... I got stuck because of missing expression somehow... so sorry ... and Thank you for helping me out.
For those who are using their smartphone to compile the application, please do check the IP Address, make sure your Phone and Laptop are connected with the same network, and do multiple checking on your code if there is something wrong with your app...
THANK YOU -
How can I use a local font on snack.expo.io?
I have a ttf font, which I would like to use as evidence on snack.expo.io, but I do not quite understand how I could do it.
Some advice?
When you are creating your snack you can import files. You can see beside Project there are three vertical dots, click that takes you to the import menu.
Selecting Import files will take you to this screen where you can either browse or drag and drop your files. I prefer to drag and drop.
You can then drag the files to the folder that you wish them to be located in.
Then to use your custom font you can follow the guide in the documentation.
https://docs.expo.io/versions/latest/guides/using-custom-fonts/
Here is a quick code example.
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { Constants, Font } from 'expo';
// You can import from local files
export default class App extends React.Component {
// <- use the button on the left, three vertical dots to import files
// set the initial state
state = {
fontLoaded: false
}
async componentDidMount() {
// load fonts
await this.loadFonts();
}
loadFonts = async () => {
// load the font
await Font.loadAsync({
'open-sans-bold': require('./assets/fonts/OpenSans-Bold.ttf'),
});
this.setState({fontLoaded: true})
}
render() {
// use the font in your text components
// only render the Text component when the font has been loaded.
return (
<View style={styles.container}>
{this.state.fontLoaded ? (<Text style={{ fontFamily: 'open-sans-bold', fontSize: 56 }}>
Hello, world!
</Text>) : null}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
}
});
And an accompanying snack to show it working, notice I have stored my fonts in the folder ./assets/fonts/ https://snack.expo.io/#andypandy/custom-font
I am implementing fb sdk in react native app. I have done all changes from link, and running in android device. App crashes on Facebook login button click and these are logs.
05-23 10:42:20.559 7063-7063/com.fbsample E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.fbsample, PID: 7063
Cannot pass a read permission (email) to a request for publish authorization
at com.facebook.login.LoginManager.validatePublishPermissions(LoginManager.java:444)
at com.facebook.login.LoginManager.logInWithPublishPermissions(LoginManager.java:416)
at com.facebook.login.widget.LoginButton$LoginClickListener.performLogin(LoginButton.java:753)
at com.facebook.login.widget.LoginButton$LoginClickListener.onClick(LoginButton.java:725)
at com.facebook.FacebookButtonBase$1.onClick(FacebookButtonBase.java:384)
at android.view.View.performClick(View.java:4785)
at android.view.View$PerformClick.run(View.java:19884)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
I searched a lot but none helped me to get rid of this issue.
At least error should contain a suggestion to do.
I am stuck from hours :/
There is nothing new from facebook doc.
I have FBLoginButton.js
import React, { Component } from 'react';
import { View } from 'react-native';
import { LoginButton } from 'react-native-fbsdk';
export default class FBLoginButton extends Component {
render() {
return (
<View>
<LoginButton
publishPermissions={["email"]}
onLoginFinished={
(error, result) => {
if (error) {
alert("Login failed with error: " + error.message);
} else if (result.isCancelled) {
alert("Login was cancelled");
} else {
alert("Login was successful with permissions: " + result.grantedPermissions)
}
}
}
onLogoutFinished={() => alert("User logged out")}/>
</View>
);
}
};
module.exports = FBLoginButton;
And App.js
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View
} from 'react-native';
var FBLoginButton = require('./FBLoginButton');
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' +
'Cmd+D or shake for dev menu',
android: 'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
type Props = {};
export default class App extends Component<Props> {
render() {
return (
<View style={styles.container}>
<Text style={styles.label}>Welcome to the Facebook SDK for React Native!</Text>
<FBLoginButton />
</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,
},
});
Some one tell why this issue persist and what can i do to resolve it.
you have to change publishPermissions={["email"]} to readPermissions={["email"]}
I changed publishPermissions={["email"]} to publishPermissions={["publish_actions"]}, and everything worked.
If you intent to get user's email. You must use readPermissions={['email']} on LoginButton from react-native-fbsdk. Please note if you already built the react native app with publishPermissions={["email"]} like in your question, remove the app and then build again.
Also, you can only use either of readPermissions or publishPermissions, not both. This is by design as documented here: https://developers.facebook.com/docs/reference/android/current/class/LoginButton/#setReadPermissions
If you want to use readPermissions and publishPermissions on the same app you must invoke the login dialog again. react-native-fbsdk provide this with LoginManager.
The LoginManager class is used to request additional permissions for a session or to provide login functionality using a custom UI. Like LoginButton, the LoginManager class is loaded from the react-native-fbsdk module. The example below performs a login with minimal permissions.
https://developers.facebook.com/docs/react-native/login
I'm trying to combine react-native and meteor using the react-native-meteor package. Meteor successfully publishes a 'dos' collection, which I have been able to subscribe to on the web client. However, after following the documentation of the react-native-meteor package (using createContainer) I am unable to subscribe; the handle is 'never ready'. When using the autopublish package from Meteor the data does load.
Versions
Meteor 1.3.4.1
react-native: 0.28.0
react-native-meteor: 1.0.0-rc14
index.ios.js
// #flow
'use strict'
import React, { Component } from 'react'
import {
AppRegistry,
StyleSheet,
View,
NavigatorIOS,
StatusBar,
Text,
} from 'react-native'
import Meteor, {
createContainer,
MeteorListView,
} from 'react-native-meteor'
Meteor.connect('ws://localhost:3000/websocket')
import GeoLocation from './app/GeoLocation'
import ConnectionInfoSubscription from './app/NetInfo'
import GridLayout from './app/GridLayout'
class DoCHANGE_0 extends Component {
renderRow(Do){
return(
<Text>{Do.joke}</Text>
)
}
render() {
const { doList, } = this.props
return (
<View style={styles.container}>
<StatusBar
barStyle="light-content"
/>
<NavigatorIOS
style = {styles.container}
barTintColor='#556270'
titleTextColor='#fff'
tintColor='#fff'
initialRoute={{
title: 'DoCHANGE',
component: GridLayout
}}/>
{!doList && <Text>Not ready with subscription</Text>}
<MeteorListView
collection="dos"
renderRow={this.renderRow}
enableEmptySections={true}
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex:1,
}
});
export default createContainer(params=>{
const handle = Meteor.subscribe('dos')
return {
doList: handle.ready(),
};
}, DoCHANGE_0)
AppRegistry.registerComponent('DoCHANGE_0', () => DoCHANGE_0);
I have found similar examples but they often don't utilise the react-native-meteor package but use the ddpclient package instead. Am I missing something obvious here? Any insights is much appreciated!
Edit:
(Meteor) /server/publish.js
Meteor.publish("dos", function() {
//console.log(Dos.find().fetch())
return Dos.find();
})
(Meteor) /both/collections.js
Dos = new Mongo.Collection('dos');
Screenshot when using autopublish from Meteor. doList handle is still not ready. But the MeteorList gets populated correctly.
Screenshot iOS autopublish on
You only included client side code in your question, but it sounds like you are missing the Meteor.publish() call on the server, if it works using autopublish but not without it!
I upgraded to newer versions of react-native, meteor, and react-native-meteor but that didn't solve the issue. However, when renaming the renderRow function to renderItem it started working.
renderRow={this.renderRow}
renderRow={this.renderItem}