A lot of the AWS API for Javascript relies on creating new AWS objects. For example, the S3 interface relies on creating an AWS object:
AWS.config.apiVersions = {
s3: '2006-03-01',
// other service API versions
};
var s3 = new AWS.S3();
It seems one needs to do this to send API requests to AWS services. However, I'm not sure how best to integrate this in React without creating new objects for every different kind of request; this seems very expensive. Is there a way of re-using the same AWS object for many different requests?
"I'm not sure how best to integrate this in React"
The best way to use the AWS SDK for JavaScript in a React app is to use version 3 and use Async Service Client calls. Your code is not version 3. The Service Client for V3 is S3Client.
Here is V3 JS code that uses Amazon S3 calls in a React app.
import React, { useState } from "javascriptv3/example_code/reactnative/App";
import { Button, StyleSheet, Text, TextInput, View } from "react-native";
import {
S3Client,
CreateBucketCommand,
DeleteBucketCommand,
} from "#aws-sdk/client-s3";
import { CognitoIdentityClient } from "#aws-sdk/client-cognito-identity";
import { fromCognitoIdentityPool } from "#aws-sdk/credential-provider-cognito-identity";
const App = () => {
const [bucketName, setBucketName] = useState("");
const [successMsg, setSuccessMsg] = useState("");
const [errorMsg, setErrorMsg] = useState("");
// Replace REGION with the appropriate AWS Region, such as 'us-east-1'.
const region = "REGION";
const client = new S3Client({
region,
credentials: fromCognitoIdentityPool({
client: new CognitoIdentityClient({ region }),
// Replace IDENTITY_POOL_ID with an appropriate Amazon Cognito Identity Pool ID for, such as 'us-east-1:xxxxxx-xxx-4103-9936-b52exxxxfd6'.
identityPoolId: "IDENTITY_POOL_ID",
}),
});
const createBucket = async () => {
setSuccessMsg("");
setErrorMsg("");
try {
await client.send(new CreateBucketCommand({ Bucket: bucketName }));
setSuccessMsg(`Bucket "${bucketName}" created.`);
} catch (e) {
setErrorMsg(e);
}
};
const deleteBucket = async () => {
setSuccessMsg("");
setErrorMsg("");
try {
await client.send(new DeleteBucketCommand({ Bucket: bucketName }));
setSuccessMsg(`Bucket "${bucketName}" deleted.`);
} catch (e) {
setErrorMsg(e);
}
};
return (
<View style={styles.container}>
<Text style={{ color: "green" }}>
{successMsg ? `Success: ${successMsg}` : ``}
</Text>
<Text style={{ color: "red" }}>
{errorMsg ? `Error: ${errorMsg}` : ``}
</Text>
<View>
<TextInput
style={styles.textInput}
onChangeText={(text) => setBucketName(text)}
autoCapitalize={"none"}
value={bucketName}
placeholder={"Enter Bucket Name"}
/>
<Button
backroundColor="#68a0cf"
title="Create Bucket"
onPress={createBucket}
/>
<Button
backroundColor="#68a0cf"
title="Delete Bucket"
onPress={deleteBucket}
/>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
},
});
export default App;
To learn how to successfully setup the AWS SDK for JavaScript in a React app, see this doc topic:
Getting started in React Native
Related
I'm a bit confused on generating SHA1 to access the Google cloud API. I have been developing an App which retrieve or display data after you login your google email, I've already used the clientID from the Google platform and paste it to my code but it doesn't work there's no error in my react mobile and I think the problem is the setup of my google API but I've already created one.
Most resources suggest to generate the `SHA1' by using the command below
keytool -list -v -keystore ./android/App/debug.keystore -alias androiddebugkey -storepass android -keypass android
Yet I see the result which generate the SHA1 but it's confusing me on how to used the generated SHA1 to google API
should I add SHA1 to google Platform console? how?
The comment/image below describes the solution to my project but I didn't understand at all
App.js
import React, { Component } from 'react';
import { View, StyleSheet, ToastAndroid, Button, Text, Image } from "react-native";
import {
GoogleSignin,
GoogleSigninButton,
statusCodes,
} from '#react-native-community/google-signin';
GoogleSignin.configure({
webClientId: '174................................9328.apps.googleusercontent.com', //sample
offlineAccess: true, // if you want to access Google API on behalf
});
class App extends Component {
constructor(props) {
super(props)
this.state = {
userGoogleInfo: {},
loaded: false
}}
signIn = async () => {
try {
console.log("asdsad");
await GoogleSignin.hasPlayServices();
const userInfo = await GoogleSignin.signIn();
this.setState({
userGoogleInfo: userInfo,
loaded: true
})
console.log(this.state.userGoogleInfo);
console.log("ok");
} catch (error) {
if (error.code === statusCodes.SIGN_IN_CANCELLED) {
console.log("e 1");
} else if (error.code === statusCodes.IN_PROGRESS) {
console.log("e 2");
} else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
console.log("e 3");
} else {
console.log(error.message);
console.log("errrorr");
}}
};
render() {
return (
<View>
<GoogleSigninButton
style={{ width: 222, height: 48 }}
size={GoogleSigninButton.Size.Wide}
color={GoogleSigninButton.Color.Dark}
onPress={this.signIn}
/>
{this.state.loaded ?
<View>
<Text>{this.state.userGoogleInfo.user.name}</Text>
<Text>{this.state.userGoogleInfo.user.email}</Text>
<Image
style={{ width: 100, height: 100 }}
source={{ uri: this.state.userGoogleInfo.user.photo }}
/>
</View>
: <Text>Not SignedIn</Text>}
</View>
);}}
export default App;
Follow below steps for add SHA1 key in your google cloud console
you need to login your google cloud console when you create project https://console.cloud.google.com/apis/credentials?authuser=1&project=<your_project_id>
Then select your project and choose Credentials left bar menu
Right side API key section and click on API key which you want to
add SHA1 and add your SHA1 key which you generated from command
click on SAVE button below within dew minutes your app will work
Refer below attachment which show where you need to place SHA1 key in google cloud console project
I tried using firebase auth service today and it worked. But after a reload, I use another number, it still worked. It returns an object even if my data is turned off, and the phone number doesn't match my current local state. But it still navigates the user into the app.
Also printing that I've exceeded my daily quota, but it still logs them in.
Decided to clear my app storage and start from begining, then an error shows up, saying the object doesn't exist.
heres the codes
THE FIRST SCREEN FOR NEW USERS, I CALL REGISTER SCREEN
import {
React,
useState,
StyleSheet,
View,
useRef,
} from '../../imports/all_RnComponents';
import {
AppInput,
InputsGroup,
AppButton,
FormTitle,
Link,
} from '../../imports/all_files';
import {PhoneInput} from '../../imports/all_packages';
import {colors, width, height, universalPadding} from '../../config/config';
const Register = ({navigation}) => {
///
const [value, setValue] = useState('');
const [formattedValue, setFormattedValue] = useState('');
const [valid, setValid] = useState(false);
const [showMessage, setShowMessage] = useState(false);
const phoneInput = useRef(null);
///
const handleSubmit = () =>
navigation.navigate('confirmation', {phoneNumber: formattedValue});
return (
<View style={styles.container}>
<FormTitle title={'Enter Phone Number'} subheading="" />
<InputsGroup>
<PhoneInput
ref={phoneInput}
defaultValue={value}
defaultCode="NG"
layout="first"
onChangeText={text => {
setValue(text);
}}
onChangeFormattedText={text => {
setFormattedValue(text);
}}
withDarkTheme
withShadow
autoFocus
/>
</InputsGroup>
<AppButton
wideButton
disabled={value.length > 10 ? false : true}
title="Send Verification Code"
// onPress={() => navigation.navigate('confirmation')}
onPress={handleSubmit}
/>
</View>
);
};
export default Register;
const styles = StyleSheet.create({
container: {
flex: 1,
width: width,
backgroundColor: colors.brandColor,
alignContent: 'center',
justifyContent: 'center',
paddingHorizontal: universalPadding,
},
});
//the Confirmation screen after inputing phone number
import {
React,
StyleSheet,
View,
useEffect,
useState,
} from '../../imports/all_RnComponents';
import {
AppInput,
InputsGroup,
AppButton,
FormTitle,
Link,
Lock,
commonFunctions,
} from '../../imports/all_files';
import {colors, width, height, universalPadding} from '../../config/config';
//firebase auth service
import auth from '#react-native-firebase/auth';
const Confirmation = ({navigation, route, choiceOfAlert = 'Phone Number'}) => {
//don't bother checking if theres a number or not, users wont get here if they dont add a number.
const {phoneNumber} = route.params;
//hold the state until firebase connects finishe...
const [initializing, setInitializing] = useState(true);
const [user, setUser] = useState();
// If null, no SMS has been sent
const [confirm, setConfirm] = useState(null);
const [code, setCode] = useState('');
const signInWithPhone = async () => {
try {
const confirmation = await auth().signInWithPhoneNumber(phoneNumber);
setConfirm(confirmation);
//if verified, navigation.navigate('mainNavigation')
} catch (error) {
commonFunctions.showToast('failed', error.message, 'error');
}
};
function onAuthStateChangedCallBack(user) {
console.log('auth is running');
if (user) {
setUser(user);
console.log(
'there is user, ',
user,
' the state user, => ',
phoneNumber,
);
//to prevent going back to login screen
navigation.navigate('welcome');
return navigation.reset({
index: 0,
routes: [{name: 'welcome'}],
});
/////////
} else
console.log(user, ' doesnt match, => ', phoneNumber);
}
useEffect(() => {
signInWithPhone();
}, []);
useEffect(() => {
const subscriber = auth().onAuthStateChanged(onAuthStateChangedCallBack);
return subscriber; // unsubscribe on unmount
}, []);
///called on manual click
const verifyPhoneNumber = async () => {
console.log(code, ' state code');
try {
await confirm.confirm(code);
} catch (error) {
console.log('Invalid code.');
}
};
return (
<View style={styles.container}>
<View style={styles.padLock}>
<Lock />
</View>
<FormTitle
title={''}
subheading={`Enter the code sent to your ${choiceOfAlert}`}
/>
<InputsGroup>
<AppInput
keyboardType="number-pad"
label="Enter Code"
onChangeText={text => {
console.log(text, ' your text');
setCode(text);
}}
/>
</InputsGroup>
<AppButton
disabled={confirm !== null ? false : true}
title="Verify"
wideButton
onPress={verifyPhoneNumber}
/>
<Link text={'re-send code'} onPress={() => signInWithPhone()} />
<Link
text={'edit phone number'}
onPress={() => navigation.navigate('register')}
/>
</View>
);
};
export default Confirmation;
const styles = StyleSheet.create({
container: {
flex: 1,
width: width,
backgroundColor: colors.brandColor,
alignContent: 'center',
justifyContent: 'center',
paddingHorizontal: universalPadding,
},
padLock: {
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
});
the code looks a bit ugly but trust me, i don't wanna get into clean code without understanding everything going on here...
for a recap..
i cleared my storage in my local app not yet published, i then deleted every user in my auth db in firebase..
I used my real number and this time...i got what i wanted smoothly...i then cleared storage out to try another time again, it printed "TOO MANY REQUESTS, THIS PROJECT HAS EXCEEDED IT QUOTAS for this operation" i still see the previous number that registered successfully in my db..
as a side note... it will be of help if i can test this phone auth with fb without getting limits cuz its just in production and i can't wait everyday to try again..
thanks in advance
As OGB also said: Firebase automatically stores user credentials in local storage, and restores them from there when the app restarts. At that point it tried to re-validates those credentials with a call to the server, and it clears them when the server rejects them (for example of the account was disabled). If the SDK can't reach the server, it assumes that the user is still signed in, until it can check with the server.
It's hard to say more without seeing the API calls you do, and the exact results you get back from them.
Update after your edit:
it will be of help if i can test this phone auth with fb without getting limits
You might want to check the documentation on Test with fictional phone numbers.
step 1:
**import auth from '#react-native-firebase/auth';**
step 2: (when click signout button)
**auth().signOut();** //This is only for Firebase Authentication. If you
//are save data in app session then also clear
//that
Firebase automatically caches data for offline use on mobile. That would explain why clearing your cache loses the data.
However, I strongly suspect you are doing something very wrong. Per the details. I can't help you though without additional info like the specific implementation
I'm trying to use the postmessage to a page opened in a webview inside a React Native App. I tried many times, but still wasn't able to send it.
I can listen to messages from the webpage normally. I just can't send anything back.
I'm currently using react-native-webview 11.6.5
export default function WebPage() {
const webviewRef = useRef();
const onMessage = (event) => {
//receive message from the web page. working here until here
const data = JSON.parse(event.nativeEvent.data);
//reply the message
webviewRef.current.postMessage(
JSON.stringify({reply: 'reply'}),
'*'
)
}
return <View>
<WebView
ref={webviewRef}
originWhitelist={['*']}
source={{ uri: 'https://robertnyman.com/html5/postMessage/postMessage.html' }}
domStorageEnabled
javaScriptEnabled
onMessage={onMessage}
/>
</View>
}
Any ideas what am I doing wrong?
UPDATE:
Thanks to #Ahmed Gaber help I was able to find this issue https://github.com/react-native-webview/react-native-webview/issues/809 and discover they're changing postMessage to injectJavaScript.
So I updated my code onMessage to the following:
const onMessage = (event) => {
const data = JSON.parse(event.nativeEvent.data);
//reply the message
webviewRef.current.injectJavaScript(
`window.postMessage(
{
reply: 'reply'
}
);`
)
}
To send data from app to webview, use injectedJavaScript
To send data from webview to app, use postMessage
To receive data in webview sent by postMessage, use onMessage
// This Js function will be injected into the web page after the document finishes loading.
// This function will Post a message to WebView.
const INJECTED_JAVASCRIPT = `(function() {
window.ReactNativeWebView.postMessage(JSON.stringify({key : "value"}));
})();`;
<WebView
source={{ uri: 'https://reactnative.dev' }}
injectedJavaScript={INJECTED_JAVASCRIPT}
onMessage={(event) => {
const data = JSON.parse(event.nativeEvent.data);
alert(data.key);
}}
/>;
React native code
function getInjectableJSMessage(message) {
return `
(function() {
document.dispatchEvent(new MessageEvent('message', {
data: ${JSON.stringify(message)}
}));
})();
`;
}
function sendDataToWebView() {
webviewRef.current?.injectJavaScript(
getInjectableJSMessage("Hello")
);
}
React web app code
React.useEffect(() => {
function handleEvent(message) {
console.log(message.data);
}
document.addEventListener("message", handleEvent);
return () =>
document.removeEventListener("message", handleEvent);
}, []);
I'm using PDFDownloadLink from the react-pdf package to generate a PDF on the fly in my application and allow the user to download a report based on data being passed to the component that generates the PDF document. However, there are more than 400 pages that need to be rendered in this PDF, and this operation blocks the main thread for a few seconds. Is there any way to make this operation asynchronous, so the rest of the application will continue to function while the PDF is being generated? Also I would like to be able to cache the results, since the data being passed to the component can come from about 8 different arrays of data, which don't change very much, so switching between these arrays I would rather not to have to render the PDF all over again if the PDF for that given array has already been generated once before... I'm guessing the blob data needs to be stored somewhere, perhaps localStorage?
import { Page, Text, View, Document, StyleSheet, PDFDownloadLink } from '#react-pdf/renderer'
const App = () => {
const condition = "firstCondition";
const filteredRowData = rowData.filter(a => a.condition = condition);
return (
<PDFDownloadLink
document={<PDF_REPORT_Document rowData={filteredRowData} />}
fileName={"PDF_REPORT.pdf"}
style={{color:'white'}}
>{({ blob, url, loading, error }) =>
loading ? "Report loading..." : "Report ready to download"
}</PDFDownloadLink>
);
}
const PDF_REPORT_Document = (props) => {
const { rowData } = props;
const styles = StyleSheet.create({
page: {
flexDirection: 'column',
backgroundColor: '#E4E4E4'
},
section: {
margin: 10,
padding: 10,
flexGrow: 1
}
});
return(
<Document>
{rowData.map((row,index) =>
<Page size="A4" style={styles.page} key={index}>
<View style={styles.section}>
<Text>Name: {row.FULLNAME}</Text>
</View>
</Page>
)}
</Document>
);
}
I finally found the answer to this in an issue on github which addresses this exact problem:
Is your feature request related to a problem? Please describe.
It is an improvement. At the moment, if you use 'PDFDownloadLink' the PDF is being generated as the component loads.
Describe the solution you'd like
It is not mandatory, but having multiple heavy PDFs ready to be downloaded wouldn't be the best approach since not every user will need it.
Describe alternatives you've considered
I've used pdf() function to generate the blob and file-saver lib to download it:
import { saveAs } from 'file-saver';
import { pdf } from '#react-pdf/renderer';
import PdfDocument from '../PdfDocument';
const generatePdfDocument = async (documentData,fileName) => {
const blob = await pdf((
<PdfDocument
title='My PDF'
pdfDocumentData={documentData}
/>
)).toBlob();
saveAs(blob, fileName);
};
export default generatePdfDocument;
I am working on a project and I need to translate speech into text I used Expo and React-native-voice.
**[Unhandled promise rejection: TypeError: null is not an object (evaluating 'Voice.onSpeechStart = null')]
- node_modules\react-native-voice\src\index.js:23:10 in removeAllListeners
- node_modules\promise\setimmediate\core.js:37:14 in tryCallOne
- ... 9 more stack frames
import React from "react";
import { StyleSheet, Text, View, TouchableOpacity } from "react-native";
import Voice from "react-native-voice";
import * as Permissions from "expo-permissions";
export default class App extends React.Component {
constructor() {
super();
this.state = {
results: [],
};
Voice.onSpeechStart = this.onSpeechStart;
Voice.onSpeechRecognized = this.onSpeechRecognized;
Voice.onSpeechEnd = this.onSpeechEnd;
Voice.onSpeechError = this.onSpeechError;
Voice.onSpeechResults = this.onSpeechResults;
Voice.onSpeechPartialResults = this.onSpeechPartialResults;
Voice.onSpeechVolumeChanged = this.onSpeechVolumeChanged;
}
async componentDidMount() {
const {status} = await Permissions.askAsync(
Permissions.AUDIO_RECORDING
);
}
componentWillMount(){
Voice.destroy().then(Voice.removeAllListeners)
}
onSpeechStart = (e)=> {
console.log('onSpeechStart',e);
};
onSpeechRecognized =(e)=>{
console.log('onSpeechRecognized',e);
}
onSpeechEnd = (e)=>{
console.log('onSpeechEnd'+e);
}
onSpeechError =(e)=>{
console.log('onSpeechError');
}
onSpeechResults = e => {
console.log('onSpeechResults'+e);
this.setState({
results: e.value,
});
}
onSpeechPartialResults = e =>{
console.log('onSpeechPartialResults' + e.value);
}
onSpeechVolumeChanged = e =>{
console.log('onSpeechVolumeChanged');
}
_startRecognizing=async()=>{
try{
await Voice.start('en-US')
} catch(e) {
console.error(e);
}
}
_stopRecognizing = async()=>{
try{
await Voice.stop()
}catch(e){
console.error(e);
}
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity
onPress={this._startRecognizing}
style={{
backgroundColor: "green",
height: 40,
width: 100,
marginBottom: 10,
}}
>
<Text style={{
fontSize: 20,
alignSelf: "center"
}}>
Starts
</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this._stopRecognizing}
style={{
backgroundColor: "red",
height: 40,
width: 100
}}
>
<Text style={{
fontSize: 20,
alignSelf: "center"
}}>
Stop
</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
from framework internals**
Update for Expo 41+
With the release of the Expo SDK 41, config plugins were added. The 3.2.0 release of react-native-voice/voice added support for config plugins.
You install the dependency as you normally would
yarn add #react-native-voice/voice
And then you must update your app.json
"expo": {
"plugins": [
[
"#react-native-voice/voice",
{
"microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone",
"speechRecogntionPermission": "Allow $(PRODUCT_NAME) to securely recognize user speech"
}
]
]
}
You will probably need to create a new build as you may get an invariant violation.
You should now read the documentation for usage
—-
Expo 40 and older
Unfortunately react-native-voice is not compatible with Expo.
The reason for this is that Expo abstracts the native iOS and Android code away from you, this makes it quick and easy to make builds and develop but the downside is that you cannot add dependencies that require you to use native code.
react-native-voice requires the use of native code. You can see this by the fact that the installation instructions require you to link the native code. See here for the documentation.
If you wish to use this dependency in your Expo project then you will need to eject it. You can find more info about ejecting, and the pros and cons of doing so on the Expo documentation website here
With Expo SDK42 you can use the react-native-voice plugin, here is what they have in the docs here
I have the same issue developing an react native app with react-native-voice package. I followed every step of the workflow (like instructed in the react-native-voice documentation as well as suggested by other answers), there seems nothing wrong -
expo run:android build successful. Then expo start --dev-client on my android emulator/physical device both throw this error:
[Unhandled promise rejection: TypeError: null is not an object
(evaluating 'Voice.isSpeechAvailable')]
In the end, I found that, one needs to open two terminals in vscode, one terminal running exp start (while connecting to your device), and the other terminal simultaneously runs expo run:android.
The app then is running on the device like a charm!
Hope this helps, and hope someone can explain more on this regarding how react-native/expo test development works?