I'm new to react and I want to show new users illustration of how my app work.
how can I achieve that?
Am I need to download something from npm?
You may use AsyncStorage for that. AsyncStorage is an unencrypted, asynchronous, persistent, key-value storage system that is global to the app. It should be used instead of LocalStorage.
import {AsyncStorage} from 'react-native';
const tutorialShown = async () => {
return await AsyncStorage.getItem('#myApp:TUTORIAL_SHOWN');
}
// somewhere in your render method
if (!tutorialShown()) {
return <Tutorial />
}
//somewhere in your Tutorial's componentDidMount
AsyncStorage.setItem('#myApp:TUTORIAL_SHOWN')
Details: https://facebook.github.io/react-native/docs/asyncstorage
Related
I'm doing a scheduler (calendar) app using React Native. You can add tasks to whatever day you want to do them. To store those tasks I'm using Firebase.
Now, I want that the tasks shown in each device are different. I though the best way to achieve this is logging the user anonymously (so that user doesn't have to sign up, which would be nonsense, in my opinion), and by doing so, only tasks owned by that user can show.
I have achieved signing up a new anonymous user (and I can see the new user in the project in Firebase web page). However, I'm struggling to make that logging last forever.
I had written this piece of code in the first function that my app renders:
useEffect(() => {
auth.onAuthStateChanged(function (user) {
if (user) {
navigation.navigate("Home");
} else {
auth.signInAnonymously().then(navigation.navigate("Home"));
}
});
});
where auth = firebase.auth(). However, each time that I reload my app, a new user is created.
Can anyone help me? Thanks in advance! :)
Have you tried to set RN persistence ?
import {
initializeAuth,
getReactNativePersistence,
} from 'firebase/auth/react-native'
import AsyncStorage from '#react-native-async-storage/async-storage'
export const auth = initializeAuth(app, {
persistence: getReactNativePersistence(AsyncStorage),
})
I have a app that conducts a test and when the currently logged in user passes the test, the app shows a modal telling him that he has passed the test. I want the app to save this state for this specific user that is currently logged in and even if he closes the app, the passing screen still remains there but now if a completely new user logs in, the app should start over from the beginning, it should show the test screen 1st and then if the user passes the test, the app saves the state for him accordingly.
Long story short, I want my app to save the state for each user separately according to their case (that rather they have passed the test or not). I want a clear and simple solution to this.
Here's the code snippet for my test.js:
import React ,{useState, useEffect} from "react";
import {View, Alert, Image, StyleSheet, Text, Modal, TouchableOpacity, TouchableHighlight} from 'react-native';
import Voice from 'react-native-voice';
import auth from '#react-native-firebase/auth';
export default alpht =({navigation}) => {
function Check() {
if (results.includes(words[index])){
Alert.alert('Correct!','You are learning so well!');
if(index==7) {
if(count<=5)
{
//displaying the modal for passing screen
setshowpass(true);
}
else{
console.log(count)
Alert.alert('fail','fail');
}
}
if (index==7){
setndis(true);
setdis(true);
setidis(true);
}
else{
setndis(false);
setdis(true);
setidis(true);
}
}
else{
Alert.alert('Ops!','Looks like you went wrong somewhere. Try again!');
setcount(count+1);
setdis(true);
setndis(true);
if(count==5){
Alert.alert('Restest', 'Looks like you had way too many mistakes!')
setind(0);
setcount(0);
setdis(true);
}
}
}
const words=['ceket', 'çilek', 'elma', 'fare', 'öğretmen', 'otobüs', 'şemsiye', 'uçak'];
const [show, setshow]=useState('');
const [showpass, setshowpass]=useState(false);
useEffect(() => {
setshow(true);
}, []);
return (
..other code here
)
}
There are multiple ways you can solve the problem. you can use AsyncStorage or build more sophisticated logic using react-redux and redux-persist.
Bottom line, you just need to cache the user details/data and you can do it following my above suggestion. (My answer doesn't need code snippet)
Thanks.
I'm using quasar with firebase 9. I'm trying to set the state with actions during the boot of the project. I have data in firebase that I want to load only once and assign to an array in the Vuex state.
there might be a way in firebase 8 but I can't solve this problem in the newer version of firebase
import { getData } from "src/firebase/config";
// load data from packages collection
export const loadPackages = async () => {
const packages = await getData("packages");
return packages;
}
// load data from menu collection
export const loadMenu = async () => {
const packages = await getData("meals-menu");
return packages;
}
I use the return of each function in the respective vue component but I want to use the return in mutating the vuex state.
any tips?
thank you
as a work around solution; try saving data from firebase into localstorage then set vuex state after localstorage is set
firebase collection has event methods to allow exactly this
Look at this as starting point: https://firebase.google.com/docs/database/web/read-and-write#read_data_once_with_an_observer
Inside event handlers you have the 'realtime' changes/added/removed data
So you can change store
Is there any way to find out that an app is about to update to a new version? I would like to call removeItem from Async Storage at that time.
Background: The current beta version (still not released) has a list which has a input field and a submit button. The first time the submit button is clicked, an alert box pops up letting the user know a couple of instructions about the workings of the application. To make this work, I have a showMessage variable in Async storage which becomes false once the message has been shown. The next version planned will have a new feature, so there are new instructions, thus I want to introduce a function that fires when the app updates. The function either remove the key value pair or make showMessage true. So when the app updates and the user clicks on the submit button for the first time, the alert box will popup with the instructions.
Just submit the next version with the new feature and the new instructions and a different key called showMessage2 which is set to true. have your app look for showMessage2 instead of showMessage. The user will get the new instructions when they get the new version, and not a moment sooner or later. The original showMessage key will be irrelevant but that's fine.
Code Push
I am using code push, here is my code for triggering a code when the app updates.
import {MMKV} from 'react-native-mmkv';
import codePush from 'react-native-code-push';
import DeviceInfo from 'react-native-device-info';
export const storage = new MMKV({
id: `version_storage`,
});
const VERSION_STORAGE_KEY = 'appVersion';
export const runThisFunctionOnAppStart = async () => {
const version = `${DeviceInfo.getReadableVersion()}-`;
const localPackage = await codePush.getUpdateMetadata();
const appVersion=localPackage?version + localPackage.label:version + 'default'
const previousVersion = storage.getString(VERSION_STORAGE_KEY);
if (previousVersion) {
if (previousVersion !== appVersion) {
//this block of code will run when app will update
}
} else {
storage.set(VERSION_STORAGE_KEY, appVersion);
}
};
NOTE: you can run runThisFunctionOnAppStart in useEffect of App.js
Without Codepush
import {MMKV} from 'react-native-mmkv';
import DeviceInfo from 'react-native-device-info';
export const storage = new MMKV({
id: `version_storage`,
});
const VERSION_STORAGE_KEY = 'appVersion';
export const runThisFunctionOnAppStart = async () => {
const appVersion = DeviceInfo.getReadableVersion();
const previousVersion = storage.getString(VERSION_STORAGE_KEY);
if (previousVersion) {
if (previousVersion !== appVersion) {
//this block of code will run when app will update
}
} else {
storage.set(VERSION_STORAGE_KEY, appVersion);
}
};
There is no function that will allow you to get notified 'if a react-native app is about to update to a new version'. Unless you're using something like CodePush, updates are handled outside of your code, and a new binary essentially just replaces your binary on the phone.
Instead, you could use a library like react-native-device-info and check the version of your app on launch or sometime before you get to your page using const version = DeviceInfo.getVersion(); You could then remove your AsyncStorage keys as appropriate for the version you detect.
We have a ReactNative app that uses redux, redux-persist and a HeadlessJS task. This task needs to have access to the store. As the task fires without booting the entire app (and so has no access by default), we thought we could simply create the store inside the task as well so that it would be rehydrated by redux-persist. It turns out, however, that the store created in this way is different from the one in the app: after running, they contain different values. We tested this in several ways and it seems indeed a problem with the stores (and not with the actions for instance)
How should we access a Redux store from an HeadlessJS task?
Relevant code:
store/configure.js:
configureStore = (client) => {
const middleware = createMiddleware(client);
const finalCreateStore = applyMiddleware(thunk, middleware, logger)(createStore);
const store = finalCreateStore(rootReducer, undefined, autoRehydrate());
return store;
};
In use (both in the app and in the service):
const client = new ApiClient();
const store = configureStore(client);
client.setStore(store);
persistStore(store, {
storage: AsyncStorage,
}
In the app we simply use the Provider from react-redux to use the store, in the service we use store.dispatch.
For people looking for solution. I have found the solution in here.
The idea is to bind the store to async method.
https://github.com/react-native-kit/react-native-track-player/issues/63
Copy pasting the solution here.
// index
const store = ...
....registerHeadlessTask('TrackPlayer', () => require('event-handler.js').bind(null, store));
// event-handler.js
module.exports = async (store, data) {
if(data.type == '...') {
store.dispatch(...);
}
};
simply create the store inside the task as well so that it would be rehydrated by redux-persist.
This did indeed happen.
You created two stores (not advisable with redux) which were both hydrate, but not linked, as there is no such thing as linked redux stores.
Every time you run createStore, it's a new store. And every time you dispatch, you do that on a specific store.
Unfortunately async or multithreaded issues are not directly addressed by redux.
It would be possible though with middleware and / or store listeners to keep the two stores in sync.
But redux is also just not a mean for communication between threads (which I assume these tasks are, or you could just give the task a reference to the store once it was created or give the main app the store reference from the task).
It's more a form of Command-Query-Separation and centralized state.
You can access your store directly as reference.
Let's say you have your headless set in index.js, then you can just simply use store there like this:
import { AppRegistry } from 'react-native';
import Store from './src/Redux/Store';
import { someAction } from './src/Redux/Actions/someActions';
import App from './App';
import { name as appName } from './app.json';
const HeadlessTask = async () => {
console.log('Receiving HeadlessTask');
const someParam = await Store.getState().Something.someParam;
if (someParam) {
Store.dispatch(someAction(someParam));
} else {
Store.dispatch(someAction());
}
};
AppRegistry.registerHeadlessTask('HeadlessTask', () => HeadlessTask);
AppRegistry.registerComponent(appName, () => App);