Can't get the userID(PlayerID). It's undefinded (ReactNative, OneSignal) - react-native

Via my application I will send notification throught OneSignal. But I can't get userID from OneSignal. I read this userID from GET request and save it in DB. After I send notification via PHP.
How I can get this userID If I always get undefined?
export default class App extends Component {
constructor(props) {
super(props);
this.WEBVIEW_REF = React.createRef();
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
OneSignal.setLogLevel(6, 0);
OneSignal.setAppId("fdb89158-4072-4964-b490-6ba70fb6b5fd");
OneSignal.promptForPushNotificationsWithUserResponse(response => {
});
OneSignal.setNotificationWillShowInForegroundHandler(notificationReceivedEvent => {
let notification = notificationReceivedEvent.getNotification();
console.log("notification: ", notification);
const data = notification.additionalData
console.log("additionalData: ", notification.additionalData);
notificationReceivedEvent.complete(notification);
});
OneSignal.setNotificationOpenedHandler(notification => {
});
OneSignal.addPermissionObserver(event => {
console.log("OneSignal: permission changed:", event);
});
OneSignal.addSubscriptionObserver(event => {
console.log("OneSignal: subscription changed to userId:", event.to.userId);
});
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton = ()=>{
this.WEBVIEW_REF.current.goBack();
return true;
}
onNavigationStateChange(navState) {
this.setState({
canGoBack: navState.canGoBack
});
}
render() {
const deviceState = OneSignal.getDeviceState();
return (
<WebView
source={{ uri: 'https://www.google.com/search?q='+ deviceState.userId}}
style={{ marginTop: 35 }}
ref={this.WEBVIEW_REF}
onNavigationStateChange={this.onNavigationStateChange.bind(this)}
/>
);
}
}

getDeviceState returns a asynchronous so make sure you're awaiting on it.

Related

React Native fingerprint authentication using react-native-fingerpirnt-scanner

I'm using react-native-fingerpirnt-scanner, the library is working fine, I just wanted to ask can we have our own fingerprint modal for authentication and add fingerprint listener to our own modal?
class BiometricPopup extends Component {
....
componentDidMount() {
if (this.requiresLegacyAuthentication()) {
this.authLegacy();
} else {
this.authCurrent();
}
}
componentWillUnmount = () => {
FingerprintScanner.release();
}
requiresLegacyAuthentication() {
return Platform.Version < 23;
}
authCurrent() {
FingerprintScanner
.authenticate({ title: 'Log in with Biometrics' })
.then(() => {
this.props.onAuthenticate();
});
}
authLegacy() {
FingerprintScanner
.authenticate({ onAttempt: this.handleAuthenticationAttemptedLegacy })
.then(() => {
...
})
....
}
handleAuthenticationAttemptedLegacy = (error) => {
...
};
renderLegacy() {
const { errorMessageLegacy, biometricLegacy } = this.state;
const { style, handlePopupDismissedLegacy } = this.props;
return (
<View style={styles.container}>
<View style={[styles.contentContainer, style]}>
...
</View>
</View>
);
}
render = () => {
if (this.requiresLegacyAuthentication()) {
return this.renderLegacy();
}
// current API UI provided by native BiometricPrompt
return null;
}
}
If anyone has made a custom modal and linked fingerprint to it then please share your code. Thanks

React Native: Getting data from Firebase

I'm simply trying to retrieve data from the database in Firebase, and here's what I've got
var userList = [];
firebase.database()
.ref('/users/')
.once('value')
.then(snapshot => {
snapshot.forEach((doc) => {
userList.push(doc.val());
});
});
console.log(userList);
Even though I copy and pasted this code from a tutorial, the userList is empty outside of the snapshot. Can you tell me why that is?
The request to firebase is asynchronous so console.log(userList); is called before userList.push(doc.val()); gets called.
You should make userList a component state variable so that when you update it your component will re render.
Something like the following should work:
class UserListComponent extends Component {
constructor(props) {
super(props);
this.state = {
userList: [],
};
}
componentDidMount() {
this.getUsers();
}
getUsers() {
firebase
.database()
.ref('/users/')
.once('value')
.then((snapshot) => {
snapshot.forEach((doc) => {
this.setState({
userList: [...this.state.userList, doc.val()],
});
});
});
}
render() {
return (
<View>
{this.state.userList.map((item) => {
return (
<View>
<Text>{item.name}</Text>
</View>
);
})}
</View>
);
}
}

How can I update a variable after render?

Hi this is my code in App.js
var music = {
name: "Starboy",
artist: "The Weeknd",
albumArt: "",
length: "4:20",
audioURL:"",
};
export default class App extends Component
{
render() {
return (
<Image style={styles.albumArt} source={{ uri:music.albumArt }} />
);
}
};
I have another function in lastFM.js
export function getAlbumArt(albumName)
{
fetch('http://ws.audioscrobbler.com/2.0/?method=album.search&album='+albumName+'&api_key=MY_API_KEY&format=json&limit=1')
.then((response) => response.json())
.then((result) => {
const image = result.results.albummatches.album[0].image[2]['#text'];
console.log(image);
return image;
})
.catch((error) => {
console.log("ERROR: "+error);
});
}
How can I update music.albumArt in App.js and re-render Image inside App.js Render?
This might help. Re-render happens when you change the state of the component. So, here we are updating the state once we get data from the API.
export default class App extends React.Component {
constructor() {
super();
this.state = {
name: "Starboy",
artist: "The Weeknd",
albumArt: "",
length: "4:20",
audioURL: ""
};
}
componentDidMount(){
fetch('http://ws.audioscrobbler.com/2.0/?method=album.search&album='+albumName+'&api_key=MY_API_KEY&format=json&limit=1')
.then((response) => response.json())
.then((result) => {
const image = result.results.albummatches.album[0].image[2]['#text'];
console.log(image);
this.setState({...this.state, albumArt: image });
})
.catch((error) => {
console.log("ERROR: "+error);
});
}
render() {
return <Image style={styles.albumArt} source={{ uri: this.state.albumArt }} />;
}
}

React Native Flat List doesn't call onEndReached handler after two successful calls

I implement a very simple list that calls a server that returns a page containing books.Each book has a title, author, id, numberOfPages, and price). I use a Flat List in order to have infinite scrolling and it does its job very well two times in a row (it loads the first three pages) but later it doesn't trigger the handler anymore.
Initially it worked very well by fetching all available pages, but it stopped working properly after I added that extra check in local storage. If a page is available in local storage and it has been there no longer than 5 seconds I don't fetch the data from the server, instead I use the page that is cached. Of course, if there is no available page or it is too old I fetch it from the server and after I save it in local storage.(Something went wrong after adding this behavior related to local storage.)
Here is my component:
export class BooksList extends Component {
constructor(props) {
super(props);
this.state = {
pageNumber: 0
};
}
async storePage(page, currentTime) {
try {
page.currentTime = currentTime;
await AsyncStorage.setItem(`page${page.page}`, JSON.stringify(page));
} catch (error) {
console.log(error);
}
}
subscribeToStore = () => {
const { store } = this.props;
this.unsubsribe = store.subscribe(() => {
try {
const { isLoading, page, issue } = store.getState().books;
if (!issue && !isLoading && page) {
this.setState({
isLoading,
books: (this.state.books ?
this.state.books.concat(page.content) :
page.content),
issue
}, () => this.storePage(page, new Date()));
}
} catch (error) {
console.log(error);
}
});
}
componentDidMount() {
this.subscribeToStore();
// this.getBooks();
this.loadNextPage();
}
componentWillUnmount() {
this.unsubsribe();
}
loadNextPage = () => {
this.setState({ pageNumber: this.state.pageNumber + 1 },
async () => {
let localPage = await AsyncStorage.getItem(`page${this.state.pageNumber}`);
let pageParsed = JSON.parse(localPage);
if (localPage && (new Date().getTime() - localPage.currentTime) < 5000) {
this.setState({
books: (
this.state.books ?
this.state.books.concat(pageParsed.content) :
page.content),
isLoading: false,
issue: null
});
} else {
const { token, store } = this.props;
store.dispatch(fetchBooks(token, this.state.pageNumber));
}
});
}
render() {
const { isLoading, issue, books } = this.state;
return (
<View style={{ flex: 1 }}>
<ActivityIndicator animating={isLoading} size='large' />
{issue && <Text>issue</Text>}
{books && <FlatList
data={books}
keyExtractor={book => book.id.toString()}
renderItem={this.renderItem}
renderItem={({ item }) => (
<BookView key={item.id} title={item.title} author={item.author}
pagesNumber={item.pagesNumber} />
)}
onEndReachedThreshold={0}
onEndReached={this.loadNextPage}
/>}
</View>
)
}
}
In the beginning the pageNumber available in the state of the component is 0, so the first time when I load the first page from the server it will be incremented before the rest call.
And here is the action fetchBooks(token, pageNumber):
export const fetchBooks = (token, pageNumber) => dispatch => {
dispatch({ type: LOAD_STARTED });
fetch(`${httpApiUrl}/books?pageNumber=${pageNumber}`, {
headers: {
'Authorization': token
}
})
.then(page => page.json())
.then(pageJson => dispatch({ type: LOAD_SUCCEDED, payload: pageJson }))
.catch(issue => dispatch({ type: LOAD_FAILED, issue }));
}
Thank you!

Can I loop componentWillMount until I get the user_key from API?

I am trying to use react navigation authentication flow to manage the login screen if the user is logged in or not. But now I got stuck in AsyncStorage. So while the user is not logged in I presume that componentWillMount will wait until the user will input the credentials, tap the login button, receive the user_id from API call and then try again. For me now it is calling what in the beginning which is fine but then I have to exit from app and go back to get the dashboard rendered. Any solution?
This is my code from App.js where I'm creating the routes as well. Also I am loading redux map on bottom.
export const createRootNavigator = (signedIn = false) => {
return SwitchNavigator(
{
SignedIn: {
screen: SignedIn
},
SignedOut: {
screen: SignedOut
}
},
{
initialRouteName: signedIn ? "SignedIn" : "SignedOut"
}
);
};
class App extends Component {
constructor(props) {
super(props);
this.state = {
signedIn: false,
checkedSignIn: false
};
}
async componentWillMount() {
await isSignedIn()
.then(res => this.setState({ signedIn: res, checkedSignIn: true }))
.catch(err => alert("An error occurred"));
}
render() {
const { checkedSignIn, signedIn } = this.state;
// If we haven't checked AsyncStorage yet, don't render anything (better ways to do this)
if (!checkedSignIn) {
return null;
}
const Layout = createRootNavigator(signedIn);
return (
<SafeAreaView style={styles.safeArea}>
<View style={{flex: 1, backgroundColor: '#ffffff'}}>
<StatusBar barStyle="light-content"/>
<Layout />
<AlertContainer/>
</View>
</SafeAreaView>
)
}
};
And here is the Auth.js where I am waiting for the user_key.
export let USER_KEY = 'myKey';
export const onSignIn = async () => { await AsyncStorage.setItem(USER_KEY, 'true') };
export const onSignOut = async () => { await AsyncStorage.removeItem(USER_KEY) };
export const isSignedIn = () => {
return new Promise((resolve, reject) => {
AsyncStorage.getItem(USER_KEY)
.then(res => {
if (res !== null) {
// console.log('true')
resolve(true);
} else {
resolve(false);
// console.log('false')
}
})
.catch(err => reject(err));
});
};
A solution would be to make use of Splashscreen. You can add a splashscreen to the App. While Splashscreen is being displayed, check if user exists in Asyncstorage, if they do, navigate user to the Dashboard/Homescreen and if asynstorage responds null, navigate user to the Login page. Once Navigation is complete, you can hide the splashscreen. Checkout this package in npmjs for Splashscreen setup react-native-splash-screen