Vuex/quasar - mutate state from firebase 9 on boot - javascript

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

Related

data querying issue when using subscribe to get real-time updates in my app

I'm coding a react native mobile application with aws amplify as my backend,
To get real-time updates in my app I used subscribe like this inside a useEffect hook,
const[cartProducts, setcartProducts] = useState <CartProduct[]>([]);
const getCartProduct = async () => {
await DataStore.query(CartProduct, c=>c.userID("eq", currentUserId))
.then(setcartProducts)
};
useEffect(() => {
const subscription = DataStore.observe(CartProduct, d=>d.userID("eq", UserId))
.subscribe(msg => getCartProduct(),);
return subscription.unsubscribe;
}, []);
the querying of data happens inside getCartProduct() function,
But the problem is whenever I close my app and reopen this screen the fetching function(getCartProduct) doesn't run
I guess because there is no change in the data (cartProducts) in the backend.
When ever I change the cartProducts data in backend then the fetching function (getCartProduct) run again
what is the solution to this?
Call getCartProduct in the useEffect block before subscribing
Wrap the getCartProduct() callback in curly brackets
Wrap subscription.unsubscribe in curly brackets and call it with ()

How to enable persistence on reactfire?

I'd like to implement Firestore offline persistence on my PWA React app using the reactfire library.
const firestore = useFirestore().enablePersistence();
let documentReference = firestore
.collection("food")
.doc("milkshake");
const { data } = useFirestoreDocData(documentReference);
but running the code i get an error:
FirebaseError: Firestore has already been started and persistence can no longer be enabled. You can only enable persistence before calling any other methods on a Firestore object.
This component is wrapped inside a <Suspense> as mentioned in the documentation
That database read is the only one that i make in the entire app, how can i solve?
Edit.
Using the example that #Ajordat gave, I've imported the preloadFirestore function inside the App component I do get an error:
"Cannot read property 'name' of undefined".
Whereas adapting (because I cannot use hooks inside the fetch function)
the example from #DougStevenson: I've imported useFirestore function in the App component (in order to get the Firestore object) to enable persistence, and then importing it (useFirestore) into my component in order to retrieve the data, but now, I get the same error as before,
Firestore has already been started and persistence can no longer be enabled.
Edit 2:
I've tried to enablePersistence without errors, thank guys, this is my approach, let me know if it is the best:
const firestore = useFirestore();
React.useEffect(() => {
firestore.enablePersistence();
}, []);
And in my custom component:
let docRef = useFirestore()
.collection("food")
.doc("milkshake");
let document = useFirestoreDocDataOnce(docRef);
console.log(document)
But now I do have a problem, when I log the document, the data are not emitted instantly, yeah I know that it is an asynchronous operation, but the component is wrapped inside a <Suspense>, in this way:
<Suspense fallback={<div>Loading</div>}>
<FoodComponent foodName={"Milkshake"} />
</Suspense>
But I don't see the loading text before the component is actually rendered.
Does the suspense fragment show the fallback component only while is loading the function (useFirestore) and not the actual data?
Well, I've solved, have to destructure the data, doing like that:
let docRef = useFirestore()
.collection("food")
.doc("milkshake");
let { data: document } = useFirestoreDocData(docRef);
console.log(document)
On other JavaScript libraries for Firestore, enablePersistence() returns a promise. That means it will complete some time in the future, with no guarantees how long it will take. If you're executing the query immediately after you call enablePersistence(), without waiting for the returned promise to become fulfilled, then you will see this error message. That's because the query "beats" the persistence layer and effectively executes first.
You will have to figure out how to use that promise to wait until it's OK to make that query with persistence enabled. For example:
seFirestore().enablePersistence()
.then(() => {
let documentReference = firestore
.collection("food")
.doc("milkshake");
const { data } = useFirestoreDocData(documentReference);
})
.catch(error => {
console.error("enablePersistence failed", error);
})
Notice how the query will complete only after the persistence is fully enabled.
Thanks for the suggestion guys #DougStevenson and #Ajordat
In app component:
import { useFirestore } from "reactfire"
...
const firestore = useFirestore();
React.useEffect(() => {
firestore.enablePersistence();
}, []);
In your custom component, where you want to use Firestore:
import { useFirestore, useFirestoreDocData /* or what you want to use */ } from "reactfire"
let docRef = useFirestore()
.collection("food")
.doc("milkshake");
let { data: document } = useFirestoreDocData(docRef);
console.log(document);

Manipulating documents in Firebase collection with Vuex [Vuex/Vuexfire]

I've a simple question but I can't find the answer.
I'm using Vuexfire to import data from Firebase in Vuex.
const state = {
ricettario: [] // data that contains all recipes (objects)
}
const actions = {
// Get data from Firebase
init: firestoreAction(({ bindFirestoreRef }) => {
bindFirestoreRef('ricettario', db.collection('ricettarioFirebase'))
}),
}
It works perfectly but I want to manipulate every document of the collection 'ricettarioFirebase'. With vue + firebase was easy, with .get() and .then()
I can't find a solution! I thought using GETTERS is the best way to do that but I'm new with Vuex and Vuexfire so I don't know how to do that.
In particular, I want to convert this (classic firebase command):
db.collection("ricettarioFirebase")
.orderBy("data")
.get()
.then(snapshot => {
snapshot.forEach(doc => {
let ricetta = doc.data();
ricetta.data = dayjs(ricetta.data)
.locale("it")
.format("D MMMM YYYY");
ricetta.diffClass = ricetta.diff.split(" ").join("_");
this.ricettario.push(ricetta);
});
});
In Vuexfire. So change every object in the "ricettario[ ]" will be "ricetta", and I want to edit the "ricetta.diffClass" and "ricetta.data"
As you will see in the Vuexfire documentation:
Vuexfire does not handle writing data back to Firebase because you can
directly use the Firebase JS SDK to precisely update whatever you
need.
The doc gives some example of use of the "standard" JS SDK, exactly like you did in your question ("classic firebase command"). So you'll have to go this way, wrapping the database writes in Vuex Actions.

check if user first visit on app with react-native

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

React Native: HeadslessJS and Redux - How to access store from task

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);

Categories

Resources