react-native-image-picker callback is not a function - android

I'm new to react native and in my sample app I can't handle properly results returned from ImagePicker of this component https://github.com/react-native-image-picker/react-native-image-picker
I'm running react 0.65 and below is my code:
import * as ImagePicker from 'react-native-image-picker';
export class App extends Component {
constructor() {
super();
this.state = { imageSource: null };
}
selectImage = () => {
const selectImageFromGallery = async () => {
const response = await ImagePicker.launchImageLibrary('library', {
selectionLimit: 1,
mediaType: 'photo',
includeBase64: true,
});
const {img64base} = response.assets[0];
this.setState({img64base});
};
selectImageFromGallery();
// console.log(resp);
}
render() {
return (
<SafeAreaView style={{justifyContent: 'center', alignItems: 'center'}}>
<Button title='Select from gallery' onPress={() => this.selectImage()} />
<Image source={this.state.imageSource} />
</SafeAreaView>
);
};
}
Upon run of application I can press button and select image, but whenever I confirm my selection it is throwing error in console and on the screen of Android device:
Uncaught Error:
'Type Error: callback is not a function'
This call stack is not sybmolicated.
I do understand that I miss to handle correctly promise or callback but I cant figure out correct syntax. Could you please help? Tried zillion of times with 'await', without await, etc. The only thing I need to stay with component class and I won't change to function class - have single calls in componentDidMount functions to make sure some specific hardware is called only once. Pease help

selectImage = async () {
const response = await ImagePicker.launchImageLibrary('library', {
selectionLimit: 1,
mediaType: 'photo',
includeBase64: true,
});
const {img64base} = response.assets[0];
this.setState({img64base});
}

Related

How do I keep the track playing even switching app or hibernating the device when using expo-av library (React Native)

I am new in React Native, so I don't master all related to background tasks, when I have to keep the app track playing even the user locks or hibernates his device.
Actually I achieved in a project that just plays a bundle track, like you can see:
import * as React from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { Audio } from 'expo-av';
export default function App() {
const [sound, setSound] = React.useState();
async function playSound() {
console.log('Loading Sound');
//On function below, could be used the following line below to get some file from ./assets folder, from device storage using require()
//method, or using loadAsync({uri:url}) to get the file from web by its url, what can be noticed in the delimited block with "*** ***"
//const { sound } = await Audio.Sound.createAsync( require('./assets/Hello.mp3')
//***
const sound = new Audio.Sound();
await sound.loadAsync({
uri: 'https://sound-library.net/wp-content/uploads/2022/08/oneheart-reidenshi-snowfall.mp3',
});
//***
setSound(sound);
console.log('Playing Sound');
await sound.playAsync();
}
React.useEffect(() => {
return sound
? () => {
console.log('Unloading Sound');
sound.unloadAsync();
}
: undefined;
}, [sound]);
return (
<View style={styles.container}>
<Button title="Play Sound" onPress={playSound} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
I would like to know how I could do that with this feature.

React Native Firebase - Push data to Array allowing to display in a FlatList

I am new to React Native and struggling a little to get this working. I have realtime database in Firebase which contains 'mechanic' names. I would like to retrieve these names and display them in a list.
I would like to display this data in a list and then execute some function when the user clicks on either name. I thought adding the database data to an array then looping through the array to add it to my FlatList.
The problem now is that when I execute the code, the this.setState({ mechanicsList: mechanicsTemp }); returns an error.
Error
[Unhandled promise rejection: TypeError: this.setState is not a function.
(In 'this.setState({]
* src\screens\FindMechanics.js:28:30 in <unknown>
- node_modules\promise\setimmediate\core.js:37:14 in tryCallOne
- node_modules\promise\setimmediate\core.js:123:25 in <unknown>
- ... 8 more stack frames from framework internals
Full Code
import React, { Component } from 'react';
import { View, Text, SafeAreaView, TouchableOpacity, ScrollView, StyleSheet } from "react-native";
import { Card } from 'react-native-elements'
import firebase from "firebase/app";
export default class FindMechanics extends Component {
constructor(props) {
super(props);
this.state = {
mechanicsList: [],
isDataLoaded: false
}
}
componentDidMount() {
var query = firebase.database().ref("MechanicList").orderByKey();
query.once("value")
.then(function (snapshot) {
let mechanicsTemp = [];
snapshot.forEach(function (childSnapshot) {
// key will be the auth ID for each user
var key = childSnapshot.key;
var mechanicName = snapshot.child(key + '/name').val();
mechanicsTemp.push({ _name: mechanicName, _key: key });
});
mechanicsList = mechanicsTemp;
() => this.setState({ mechanicsList: mechanicsTemp }); // This does not execute it seems - main problem I believe
//this.setState({ mechanicsList: mechanicsTemp }); - This return a warning 'this.setState is not a function'
console.log(mechanicsList); //Prints data as expected
mechanicsTemp.forEach((mechanic) => {
console.log( mechanic._name); //Prints data as expected
});
});
}
render() {
//The Card element is empty - nothing shows.
console.log(this.state.mechanicsList) //This return Array [] which indicates it is empty
return (
<SafeAreaView style={styles.container}>
<ScrollView horizontal={true}>
<TouchableOpacity>
<Card style={styles.card}>
{
this.state.mechanicsList.map((u, i) => {
return (
<View key={i}>
<Text>{u._key}</Text>
<Text>{u._name}</Text>
</View>
);
})
}
</Card>
</TouchableOpacity>
</ScrollView>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#FFF'
},
paragraph: {
margin: 24,
fontSize: 18,
textAlign: 'center',
},
card: {
flex: 1,
width: '80%',
},
});
Console
Finished building JavaScript bundle in 384ms.
Running application on Android SDK built for x86.
Array []
1st thing, you have mechanics object in state so you need to access it like
console.log(this.state.mechanics)
2nd thing is that you are not updating state variable when you are having data, it should be like following
let mechanicsTemp = [];
snapshot.forEach(function (childSnapshot) {
// key will be the auth ID for each user
var key = childSnapshot.key;
var mechanicName = snapshot.child(key + '/name').val();
mechanicsTemp.push({_name: mechanicName, _key: key});
});
this.setState({ mechanics:mechanicsTemp })
I dunno if you still need help with this or not but I just used your code and I solved this.setState problem with binding. You can either use arrow function or bind your function:
.then(function (snapshot) {
// ..
}.bind(this));

Cancel a fetch request in react-native

Is there any way to abort a fetch request on react-native app ?
class MyComponent extends React.Component {
state = { data: null };
componentDidMount = () =>
fetch('http://www.example.com')
.then(data => this.setState({ data }))
.catch(error => {
throw error;
});
cancelRequest = () => {
//???
};
render = () => <div>{this.state.data ? this.state.data : 'loading'}</div>;
}
i tried the abort function from AbortController class but it's not working !!
...
abortController = new window.AbortController();
cancelRequest = () => this.abortController.abort();
componentDidMount = () =>
fetch('http://www.example.com', { signal: this.abortController.signal })
....
Any help please !
You don't need any polyfill anymore for abort a request in React Native 0.60 changelog
Here is a quick example from the doc of react-native:
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* #format
* #flow
*/
'use strict';
const React = require('react');
const {Alert, Button, View} = require('react-native');
class XHRExampleAbortController extends React.Component<{}, {}> {
_timeout: any;
_submit(abortDelay) {
clearTimeout(this._timeout);
// eslint-disable-next-line no-undef
const abortController = new AbortController();
fetch('https://facebook.github.io/react-native/', {
signal: abortController.signal,
})
.then(res => res.text())
.then(res => Alert.alert(res))
.catch(err => Alert.alert(err.message));
this._timeout = setTimeout(() => {
abortController.abort();
}, abortDelay);
}
componentWillUnmount() {
clearTimeout(this._timeout);
}
render() {
return (
<View>
<Button
title="Abort before response"
onPress={() => {
this._submit(0);
}}
/>
<Button
title="Abort after response"
onPress={() => {
this._submit(5000);
}}
/>
</View>
);
}
}
module.exports = XHRExampleAbortController;
I've written quite a bit actually about this subject.
You can also find the first issue about the OLD lack of AbortController in React Native opened by me here
The support landed in RN 0.60.0 and you can find on my blog an article about this and another one that will give you a simple code to get you started on making abortable requests (and more) in React Native too. It also implements a little polyfill for non supporting envs (RN < 0.60 for example).
You can Actually achieve this by installing this polyfill abortcontroller-polyfill
Here is a quick example of cancelling requests:
import React from 'react';
import { Button, View, Text } from 'react-native';
import 'abortcontroller-polyfill';
export default class HomeScreen extends React.Component {
state = { todos: [] };
controller = new AbortController();
doStuff = () => {
fetch('https://jsonplaceholder.typicode.com/todos',{
signal: this.controller.signal
})
.then(res => res.json())
.then(todos => {
alert('done');
this.setState({ todos })
})
.catch(e => alert(e.message));
alert('calling cancel');
this.controller.abort()
}
render(){
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button title="Do stuff" onPress={() => { this.doStuff(); }} />
</View>
)
}
}
So basically in this example, once you click the 'doStuff' button, the request is immediately cancelled and you never get the 'done' alert. To be sure, it works, try and comment out these lines and click the button again:
alert('calling cancel');
this.controller.abort()
This time you will get the 'done' alert.
This is a simple example of hoe you can cancel a request using fetch in react native, feel free to adopt this to your own use case.
Here is a link to a demo on snackexpo https://snack.expo.io/#mazinoukah/fetch-cancel-request
hope it helps :)
the best solution is using rxjs observables + axios/fetch instead of promises, abort a request => unsubscribe an observable :
import Axios from "axios";
import {
Observable
} from "rxjs";
export default class HomeScreen extends React.Component {
subs = null;
doStuff = () => {
let observable$ = Observable.create(observer => {
Axios.get('https://jsonplaceholder.typicode.com/todos', {}, {})
.then(response => {
observer.next(response.data);
observer.complete();
})
});
this.subs = observable$.subscribe({
next: data => console.log('[data] => ', data),
complete: data => console.log('[complete]'),
});
}
cancel = () =>
if (this.subs) this.subs.unsubscribe()
componentWillUnmount() {
if (this.subs) this.subs.unsubscribe();
}
}
That is it :)

React Native `new Function()` does not support ES6 syntax

CMD:
react-native init Test && react-native run-android
App.js:
export default class App extends Component {
render() {
new Function("person", "const { firstname } = person; alert(firstname);")({ firstname: "Test" });
}
}
Whenever the new function gets constructed and invoked, the app crashes stating: "SyntaxError: Unexpected token '{'. Expected an identifier name in const declaration" Only happens on Android.
Any help would be appreciated. Thanks!
React Native: v0.55.7
The react native documentation indicates that JavaScriptCore is generally used at runtime (V8 during debugging), but it's light on specifics as to how it is configured. One thing it does mention is that the native JavaScriptCore is used on iOS, while a different version is bundled with the app for user on Android.
Because Babel is used at compile time with react native to support ES5/ES6 features, it may be that the runtime is configured at a lower level of support. So when attempting to create code from a string at runtime, you may actually be running with a JavaScript interpreter that doesn't understand e.g., destructuring syntax.
You could try using Babel's transform at runtime to transpile your code:
import {transform} from 'babel-core';
export default class App extends Component {
render() {
const f = 'const { firstname } = person; alert(firstname);';
const result = transform(f, {
presets: ['es2015']
});
new Function("person", result.code)({ firstname: "Test" });
}
}
Can you create a const with a dynamic name? If it's possible, sorry about my lack of knowledge about that subject.
The error message said that a name to variable const is expected.
I hope it has been useful.
Best regards.
Try to change the style you create that function. In React Native is common to see arrow functions, that must be created outside your render method.
Note that your render method will be trigger every single time that your state changes. and it would be a waste of memory resources and unnecessary computing time
import React, {
Component
} from 'react';
import {
Text,
View,
StyleSheet
} from 'react-native';
export default class App extends Component {
//your custom function
myFunc = (param) => {
console.log(param)
return param
}
//your render method
render() {
const param = "Im a text"
//you could do this... i would never do that..
const myFuncInRender = () => { console.log('Im a stupid func')}
const myStupidFunc2 = new Function("person", "const { firstname } = person; alert(firstname);")({ firstname: "Test" });
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
{this.myFunc(param)/* HERE is where you call the func*/}
</Text>
</View>
);
}
} // end from Class
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
alignItems:'center',
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});

How to setParams in `Screen` when use `TabNavigator`(ES6)?

(Android React-Native 0.47)
How could i do to give the two PopularTab diff params and get this params in PopularTab, I've try many times ,but failed.
the only params i can get is navigation.key and navigation.routeName:
const Popular = TabNavigator({
IOS: {
screen: PopularTab,
//I try to code here to set the params but fail.
//eg: data: 'param1'
},
Android: {
screen: PopularTab,
},
},
{
tabBarPosition: 'bottom',
tabBarOptions: {
activeTintColor: '#e91e63',
}
}
);
There are three ways to achieve this, see which suits your need.
1. Suggest to do this official way, via screenProps
screenProps seems also suit your needs, with unidirectional design pattern.
helper function
function ScreenWithDefaultParams(Comp, defaultParams) {
return class extends Component {
render() {
return (<Comp {...this.props} screenProps={defaultParams} />)
}
}
}
TabNavigation definition
IOS: {
screen: ScreenWithDefaultParams(PopularTab, {test: 'default'})
},
And then you can get it inside PopularTab:
class PopularTab extends Component {
render() {
/* get default screenProps */
console.log('default screenProps here!', this.props.screenProps);
}
}
2. Workaround for set default navigation params
Although it works, there's some problem with it. Firstly, as you see you got warning about Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, that is because every time you call setParams, navigationOptions will be trigger again so react-native warn you that might be an anti-pattern, or might cause an infinite loop.
Although we know it won't be an infinite loop, the warning won't disappear because react-native compiler never satisfied with it.
helper function
function setDefaultParams(nav, defaultParams) {
const { state, setParams } = nav.navigation;
const params = state.params || {};
let token = btoa(JSON.stringify(defaultParams));
if (params[token]) return;
setParams({ [token]: true, ...defaultParams });
}
TabNavigation definition
IOS: {
screen: PopularTab,
navigationOptions: (nav) => {
setDefaultParams(nav, {test: 'default'});
}
},
And then you can get it inside PopularTab:
class PopularTab extends Component {
render() {
const { state, setParams, navigate } = this.props.navigation;
const params = state.params || {};
/* get default set params */
console.log('default param here!', params.test);
}
}
3. set component props in navigators
If you want to make it happens with normal Component props:
TabNavigation definition
IOS: {
screen: (props) => <PopularTab {...props} test='default' />,
},
And then you can get it inside PopularTab:
class PopularTab extends Component {
render() {
/* get default props */
console.log('default props here!', this.props.test);
}
}

Categories

Resources