how to store user input data in your react native app - react-native

i know its possible to store data using local storage for a web app but how would i do this for a react native app. the app I've made allows the user to enter a phone number into the input field and it will call that number. I also have a login page. I would like the last number they entered into the input field still be there when they re open the app. heres the code below
<View>
<Text style={styles.phoneNumberTitle}>PHONE NUMBER</Text></View>
<TextInput style={styles.inputs}
ref={(el)=>{this.recipient=el;}}
onChangeText={(recipient)=>this.setState({recipient})}
value={this.state.recipient}/>
<Button title="CALL"
style={styles.callButtCont}
onPress={this.setTimer.bind(this)} />

UPDATE:
AsyncStorage is Deprecated. Use react-native-community/react-native-async-storage instead.
ORIGINAL ANSWER:
AsyncStorage is a simple, unencrypted, asynchronous, persistent, key-value storage system that is global to the app. It should be used instead of LocalStorage.
import AsyncStorage at the top :-
import { AsyncStorage} from 'react-native'
set like this :-
AsyncStorage.setItem("recipient", this.state.recipient);
and access like this :-
AsyncStorage.getItem("recipient").then((value) => {
alert("Get recipient >> ", value);
}).done();
Reference: https://facebook.github.io/react-native/docs/asyncstorage.html

Related

Passing Login Details to React Native WebView

I'm trying to pass login details to a WebView, basically, my use case is, I have a login page built with React Native, after a successful login I wanted to redirect the user to a WebView login with the login details so the WebView doesn't render the login page in itself. So, to achieve this I attach the ref to webView like so
<WebView ref={webViewRef} ... />
With the login page built with ReactNative, the user will enter their credentials, once the login is successful I'll get the user details from the backend as a response to the LOGIN Post API Call, so I passed the response to the postMessage function
const response = await LOGIN({...credentials});
webviewRef.current.postMessage(response.data);
And to the React Web app, I used the below code to add the listener
window.addEventListener("message", (message) => {
alert(JSON.stringify(message.data));
});
But, I'm not getting the data with message.data.
Any workaround would highly be appreciated
You have to use injectJavaScript method on the webviewRef to send data from the app to the web(i.e., to react side). The post message will be used vice-versa i.e., to send data from react side to the app side. The solution below would solve your issue.
First on react side, set the custom function on the window object.
window.onUserLogin = function(userDetails) {
alert(`userDetails are ${JSON.stringify(userDetails)}`)
}
Now on the react-native side, you have the webViewRef. Using that please make the below call.
const USER_DETAILS = {
userName: "Haider"
};
webViewRef.current.injectJavaScript(`window.onUserLogin(${JSON.stringfy(USER_DETAILS)});true;`)

Json form schema use in react native

Is there any way I can use json form schema with custom renderer (using json schema to render react native UI elements) in react native.
I have seen couple of react native specific package which are inspired by json form but couldn't get those working as per the requirement.
I am also looking to use it with yup form validation package
Thanks.
Yes, it is possible to use a JSON form schema with a custom renderer to render React Native UI elements in a React Native app. There are several packages available that can help you achieve this, such as react-jsonschema-form and json-schema-form-generator.
To use a JSON form schema with a custom renderer in React Native, you will need to first install one of the above packages (or a similar one) using npm or yarn. Then, you can use the Form component provided by the package to define your form schema and specify the custom renderer that you want to use.
For example, to use the react-jsonschema-form package, you could do the following:
import { Form } from 'react-native-jsonschema-form';
const schema = {
// your JSON form schema here
};
const uiSchema = {
// your custom renderer here
};
const MyForm = () => (
<Form schema={schema} uiSchema={uiSchema} />
);
Once you have defined your form, you can use the yup form validation package to validate the form values when the user submits the form. To do this, you can use the validate option of the Form component, passing in a yup validation schema to validate the form values against.
For example:
import * as yup from 'yup';
const schema = yup.object().shape({
// your yup validation schema here
});
const MyForm = () => (
<Form schema={schema} uiSchema={uiSchema} validate={validate} />
);

Why doesn't ref.current.focus() work when running tests via the #testing-library/react-native libary?

I'm attempting to write some tests for my react native app. A component in my app focuses a TextInput after a parent Pressable receives a press. I'm using a ref to identify and focus the TextInput element.
My desired functionality works just fine when running my app through expo, but my test is failing because it seems that the onFocus event is not being called.
Why isn't ref.current.focus() being called when running tests via the #testing-library/react-native library?
Here's my code:
Foo.js
import {Pressable, TextInput} from "react-native";
import {useRef} from "react";
const Foo = (props) => {
const inputRef = useRef()
return (
<Pressable testID={"pressable"} onPress={() => inputRef.current.focus()}>
<TextInput ref={inputRef} testID={"input"} onFocus={props.onFocus} />
</Pressable>
)
}
export default Foo;
Foo.test.js
import { render, screen, fireEvent } from '#testing-library/react-native';
import Foo from "./foo";
test('onFocus is called after press', () => {
const mockFocus = jest.fn();
render(<Foo onFocus={mockFocus} />)
// fireEvent(screen.getByTestId("input"), 'focus');
fireEvent.press(screen.getByTestId("pressable"));
expect(mockFocus).toHaveBeenCalled()
});
This test fails with the following message:
Error: expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
I created an issue on the RNTL GitHub page and received a response from a contributor. Copying and pasting here for easy reference for anyone who might stumble upon this thread.
This is expected as React Test Renderer which we use for rendering
does not support refs. Check #1006 for more details.
Since the behaviour of focus() triggering onFocus event would probably
involve roundtrip to native side (from JS side), then you actually
cannot test such behaviour using RNTL as we do not run native code (see
here for details).
That leaves you with following options:
Call fireEvent.focus to manually trigger onFocus on relevant
TextInput. Recommended in case focus assertion would be a part of a
step in a bigger test.
Use createNodeMock to pass ref creating function to render method, More details here. Recommended in case you
just want to assert pressing button triggers onFocus.

Saving data in React Native

Link to the File Structure Photo
So I'm currently learning React Native and assuming a file structure shown in the photo. I would like the user to click a button such that the button saves some text to a txt file under resources. How would I go about doing that?
I have tried AsyncStorage, fn-fetch-blob, react-native-filesystem but they have failed (not sure if those libraries are meant to be for specific file directories on your phone device)
What I have so far is a code shown below where if the user clicks the "Create file" button, then it saves to a text file called "my-file.txt" under the same directory as where the current .js file is, which well doesn't work
import FileSystem from 'react-native-filesystem'
export default class SaveData extends React.Component {
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={this.createFile}>
<Text>Save to file</Text>
</TouchableOpacity>
</View>
);
}
createFile = async () => {
const fileContents = 'This is some content.';
await FileSystem.writeToFile('./my-file.txt', fileContents);
}
}
What you are trying to do here is not possible. There is no way of accessing these directories when your app is running. This is not the same as when you are running on a computer (a node.js app for example). This file structure will not be available when you are running in a native environment.
Async storage is not used to save files. It is used to save values, so it will never work for what you are trying to accomplish here.
The closest thing to what you are trying to do would be to use react-native-fetch-blob and store the file in the file system of the device, which is also the correct way of storing a file on a mobile device.

Does react native has auto signin concept?

I am newbie to react native. I have created login, home and logout screens. If i close my app without logging out and open my app again then it should redirect to home screen from login without asking the user to enter the login credentials.
Can i store a global variable with login details and a flag and delete them when user clicks on logout? or is there any other way to do it?
You can use AsyncStorage. AsyncStorage is a simple, unencrypted, asynchronous, persistent, key-value storage system that is global to the app. It should be used instead of LocalStorage.
It is recommended that you use an abstraction on top of AsyncStorage instead of AsyncStorage directly for anything more than light usage since it operates globally.
To store data:
await AsyncStorage.setItem('#MySuperStore:key', 'I like to save it.');
To Fetch data:
const value = await AsyncStorage.getItem('#MySuperStore:key');
if (value !== null){
// We have data!!
console.log(value);
}
To remove data:
AsyncStorage.clear();
After getting response from login API, store userid in AsyncStorage and on logout click you can clear AsyncStorage.