react native play sound on event - react-native

I have a component like:
import React, { Component } from 'react'
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native'
class MovieList extends Component {
handlePress() {
// Play some sound here
}
render() {
const { movie } = this.props
return (
<TouchableOpacity onPress={this.handlePress.bind(this)}>
<View style={styles.movie}>
<Text style={styles.name}>{movie.name}</Text>
<View style={styles.start}>
<Text style={styles.text}>Start</Text>
</View>
</View>
</TouchableOpacity>
)
}
}
Here when I touch the view I want to play some sound.
I have googled about it but not found any appropriate answer
Is there anyway I can play sound when I press to something?
How can I do this ?

Check out React Native Sound - a cross platform component for accessing device audio controls.
You can use it like so:
const Sound = require('react-native-sound')
let hello = new Sound('hello.mp3', Sound.MAIN_BUNDLE, (error) => {
if (error) {
console.log(error)
}
})
hello.play((success) => {
if (!success) {
console.log('Sound did not play')
}
})

You can try Audio component from expo-sdk.
Check an example here.
It works with sdk 18.

You can play the sound with the expo-av library like this.
import { Audio } from "expo-av";
class MovieList extends Component {
async handlePress() {
try {
const { sound: soundObject, status } = await
Audio.Sound.createAsync('sound.mp3', { shouldPlay: true });
await soundObject.playAsync();
} catch (error) { console.log(error); }
}
render() {
const { movie } = this.props
return (
<TouchableOpacity onPress={this.handlePress.bind(this)}>
<View style={styles.movie}>
<Text style={styles.name}>{movie.name}</Text>
<View style={styles.start}>
<Text style={styles.text}>Start</Text>
</View>
</View>
</TouchableOpacity>
)
}
}

Related

expo AppLoading startAsync Deprecated. what is the alternative?

I am learning react native from Udemy. In one of the lessons I saw AppLoading has been used for loading fonts.
So i want to learn about it in documentation from here. I am able to use that without any issues even though, I saw here that startAsync has been deprecated.
What is the alternative to this startAsync if it stopped working?
below is the code from documentation,
import React from 'react';
import { Image, Text, View } from 'react-native';
import { Asset } from 'expo-asset';
import AppLoading from 'expo-app-loading';
export default class App extends React.Component {
state = {
isReady: false,
};
render() {
if (!this.state.isReady) {
return (
<AppLoading
startAsync={this._cacheResourcesAsync}
onFinish={() => this.setState({ isReady: true })}
onError={console.warn}
/>
); }
return (
<View style={{ flex: 1 }}>
<Image source={require('./assets/snack-icon.png')} />
</View>
);
}
async _cacheResourcesAsync() {
const images = [require('./assets/snack-icon.png')];
const cacheImages = images.map(image => {
return Asset.fromModule(image).downloadAsync();
});
return Promise.all(cacheImages);
}
}
Call _cacheResourcesAsync function in componentDidMount and when all promised are resolved set state isReady to true like:
import React from 'react';
import { Image, Text, View } from 'react-native';
import { Asset } from 'expo-asset';
import AppLoading from 'expo-app-loading';
export default class App extends React.Component {
state = {
isReady: false,
};
componentDidMount(){
_cacheResourcesAsync();
}
render() {
if (!this.state.isReady) {
return (
<AppLoading />
); }
return (
<View style={{ flex: 1 }}>
<Image source={require('./assets/snack-icon.png')} />
</View>
);
}
_cacheResourcesAsync() {
const images = [require('./assets/snack-icon.png')];
const cacheImages = images.map(image => {
return Asset.fromModule(image).downloadAsync();
});
Promise.all(cacheImages).then(()=>{
this.setState({ isReady : true });
});
}
}
You should use a hook to load your images.
First, create a hook to load resources in a separate file:
import * as SplashScreen from 'expo-splash-screen';
import { useEffect, useState } from 'react';
export default function useCachedResources() {
const [isLoadingComplete, setLoadingComplete] = useState(false);
// Load any resources or data that we need prior to rendering the app
useEffect(() => {
async function loadResourcesAndDataAsync() {
try {
SplashScreen.preventAutoHideAsync();
// Load images
const images = [require('./assets/snack-icon.png')];
await images.map(async image =>
await Asset.fromModule(image).downloadAsync());
} catch (e) {
// We might want to provide this error information to an error reporting service
console.warn(e);
} finally {
setLoadingComplete(true);
SplashScreen.hideAsync();
}
}
loadResourcesAndDataAsync();
}, []);
return isLoadingComplete;
}
Then call it in your App component - I changed it to a function component, because hooks don't work in classes and it is now the recommended way of coding react:
import { Image, View } from 'react-native';
import useCachedResources from "./hooks/useCachedResources";
export default function App() {
const isLoadingComplete = useCachedResources();
if (!isLoadingComplete) {
return null;
}
return (
<View style={{ flex: 1 }}>
<Image source={require('./assets/snack-icon.png')} />
</View>
);
}

onPress is called automatically while using NetInfo - react native

NetInfo is used to check the connection & theres a checkNetwork function called in onPress of TouchableOpacity. When the button is clicked once, the checkNetwork
function is called automatically multiple times without tapping the button when the network connection is lost and vice versa.
Please have a look at the code here:
Please have a look at the video
export default class App extends React.Component {
checkNetwork = () => {
NetInfo.addEventListener((state) => {
if (state.isConnected) {
alert('isConnected');
} else {
alert('not connected');
}
});
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity
activeOpacity={0.8}
onPress={()=> this.checkNetwork()}>
<Text>Check here</Text>
</TouchableOpacity>
</View>
);
}
}
You should not declare event listener inside of the click itself,
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {alert: ''};
}
componentDidMount() {
NetInfo.addEventListener((state) => this.setState({ alert: state.isConnected ? 'isConnected' : 'not connected'})
}
checkNetwork = () => alert(this.state.alert)
render() {
return (
<View style={styles.container}>
<TouchableOpacity
activeOpacity={0.8}
onPress={()=> this.checkNetwork()}>
<Text>Check here</Text>
</TouchableOpacity>
</View>
);
}
}
though in your case event listener isn't exactly the fit logic for UI behavior of pressing button, so I think you might wanna use useNetInfo
import {useNetInfo} from "#react-native-community/netinfo";
class App extends React.Component {
checkNetwork = () => {
if (this.props.netInfo.isConnected) {
alert('isConnected');
} else {
alert('not connected');
}
});
};
...rest render...
}
export default () => <App netInfo={useNetInfo()} />

React Native Expo Camera Preview is not showing

I'm new to React Native and I wanted to implement the camera component from Expo to use it, I followed the tutorial given in the documentation but it didn't work for me. Here is the code I used in my Camera js file:
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { Camera, Permissions } from 'expo';
export default class CameraApp extends Component {
state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
}
async componentWillMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({
hasCameraPermission: status === 'granted'
});
}
render() {
const { hasCameraPermission } = this.state;
if(hasCameraPermission === null) {
return <Text>Hello</Text>;
} else if(hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else {
return (
<View style={{flex: 1}}>
<Camera type={this.state.type} style={{flex: 1}}/>
</View>
);
}
}
}
and added it to the render method in App.js like this using native-base:
render() {
if(this.state.fontLoaded === true) {
return (
<Container>
<View style={{flex: 1}}>
<HeaderNoLeft />
</View>
<Content>
<View style={{flex: 1}}>
<CameraApp />
</View>
</Content>
</Container>
);
} else {
return <Expo.AppLoading />;
}
}
}
What could be the problem? I can't seem to understand why is the camera preview not showing in the app and I'm stuck to this. Any help is appreciated.
Try giving a height parameter instead of flex, flex didn't work for me either.
<Camera type={this.state.type} style={{height: 300}}/>
It's not a good solution but seeing the problem is about styling is something.
Instead : const { status } = await Permissions.askAsync(Permissions.CAMERA);
Try this:
import * as Permissions from "expo-permissions";
...
const { status } = await Permissions.askAsync(Permissions.CAMERA);

undefined is not an object(evaluating '_this.refs.toast.show')

My aim is to listen the event for Android homeback button, and then give a toast when continuous click. Here the third component "react-native-easy-toast" is used, fully code snippets shown as below:
import React, { Component } from 'react';
import {View, WebView, Platform, BackHandler, StyleSheet} from 'react-native';
import Toast, {DURATION} from 'react-native-easy-toast';
export default class HomeScreen extends Component {
constructor (props) {
super(props);
}
onNavigationStateChange = (event) => {
this.setState({
navCanGoBack : event.canGoBack,
});
};
componentDidMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('hardwareBackPress', this.onHomeBackPress);
}
}
onHomeBackPress = () => {
if (this.state.navCanGoBack) {
this.refs['webview'].goBack();
return true;
} else {
//exit app if exceed 2 seconds
if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
return false;
}
this.lastBackPressed = Date.now();
this.refs.toast.show('weill exit app press again');
return true;
}
};
render() {
return (
<View style={{flex:1}}>
<WebView
source={{ uri: 'http://www.test.com/' }}
style={{ width: '100%', height: '100%' }}
ref="webview"
onNavigationStateChange={this.onNavigationStateChange}
/>
<Toast ref="toast" />
</View>
);
}
}
Finally, run the app and error given:
undefined is not an object(evaluating '_this.refs.toast.show')
I am newer to React Native.
Please try
//inside constructor
this.toastRef = React.createRef();
...
<Toast ref={this.toastRef} />
and replace
this.refs.toast.show('weill exit app press again');
to
this.toastRef.current.show('weill exit app press again');

Sharing strings to other native applications not working in react native

I have been following this tutorial, however, when I go to run the application after dropping the code in, it doesn't seem to work. The tutorial seems fairly simple, so I can not understand why it is not working.
The error message I'm getting is:
import React from 'react'
import { View, Text, StyleSheet, Image, Share } from 'react-native'
class ShareLesson extends Component {
constructor(props) {
super(props);
this._shareMessage = this._shareMessage.bind(this);
this._showResult = this._showResult.bind(this);
this.state = { result: ''};
}
_showResult(result) {
this.setState({result});
}
_shareMessage() {
Share.share({
message: 'This is a simple shared message'
}).then(this._showResult);
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight onPress={this._shareMessage}>
<Text style={styles.welcome}>
Share
</Text>
</TouchableHighlight>
<Text>
{JSON.stringify(this.state.result)}
</Text>
<View>);
}
}
Tabs Component
class Tabs extends Component {
_changeTab (i) {
const { changeTab } = this.props
changeTab(i)
}
_renderTabContent (key) {
switch (key) {
case 'today':
return <Home />
case 'share':
return <Share />
case 'savequote':
return <SaveQuote />
case 'moremenu':
return <MoreMenu />
}
}
render () {
const tabs = this.props.tabs.tabs.map((tab, i) => {
return (
<TabBarIOS.Item key={tab.key}
icon={tab.icon}
selectedIcon={tab.selectedIcon}
title={tab.title}
onPress={() => this._changeTab(i)}
selected={this.props.tabs.index === i}>
{this._renderTabContent(tab.key)}
</TabBarIOS.Item>
)
})
return (
<TabBarIOS tintColor='black'>
{tabs}
</TabBarIOS>
)
}
}
export default Tabs