How to use onSnapshot to update props through Redux - javascript

I'm learning how to code and I'm really struggling with the following issue:
I'm building a chat app and I need to display new messages as soon as they are submitted. As a result, I thought about using onSnapshot(). Every time I used onSnapshot() in basic one-page exercises, it worked. Now, however, I have a project with 3 folders (src; public; functions). For all my functionality, I got/sent data using this.props.functionName() and manage state with Redux and then, the backend would return a promise.
My question is, how do I use onSnapshot to update my props given that I cannot call the function nor use return.
I tried using the admin sdk directly in the components, but firebase issued a warning in the console saying I should only use it in the backend.
Basically, how do I send the following array to the component I need it to be sent to without invoking the function?
exports.messages = (req, res) => {
db.collection('messages').onSnapshot(snapshot => {
let messages = [];
snapshot.forEach(doc => {
messages.push(doc.data())
});
})
}
Thanks in advance!

You can find in this tutorial a way to update firebase props that might work for you. The sample code they use is:
useEffect(() => {
const unsubscribe = props.firebase
.db.collection('myCollectionName')
.onSnapshot(snapshot => {
if (snapshot.size) {
// we have something
** Handle returned data **
} else {
// it's empty
}
})
return () => {
unsubscribe()
}
}, [props.firebase])
And this other one for handling returned data:
let myDataArray = []
snapshot.forEach(doc =>
myDataArray.push({ ...doc.data() })
)
setData(myDataArray)

Related

How to use manual cache updates using RTK Query

I have recently started working on redux toolkit, Basically i want to refetch the data from database if there is mutation. I am using flatlist in my react native project where on pull to refresh i want my "getPosts" endpoint to refetch and get updated.
Note: I know about using tags for automated cache invalidation. but on web RTK query is not implemented.
Talking about pessimistic update:
async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {
try {
const { data: updatedPost } = await queryF`enter code here`ulfilled
const patchResult = dispatch(
api.util.updateQueryData('getPost', id, (draft) => {
Object.assign(draft, updatedPost)
})
)
} catch {}
},
just give a help how to call this function from APP.JS or anywhere from the app. Thanks
You can just call refetch, you don't need anything that complicated. See the docs on useQuery
const myResult = useMyquery(args)
// in your pull to refresh trigger:
myResult.refetch()
If you are outside of a component, you can also still
store.dispatch(api.endpoints.myEndpoint.initiate(args, { track: false })))
to trigger a refetch

Svelte: How to manually stop subscribe?

I have a store that fetches data once in a while – according to user's actions. This is a store because its data is used globally and mainly all components needs the latest data available.
But, for one specific component, I only need the first data loaded.
For this component, there is no reason to keep a subscribe() function running after the first fetch. So, how can I stop this subscribe function?
The only example in Svelte doc's uses onDestroy(), but I need to manually stop this subscribe().
I tried with a simple "count" (if count > 1, unsubscribe), but it doesn't work.
import user from './store'
let usersLoaded = 0
const unsubscribe = user.subscribe(async (data) => {
if(data.first_name !== null) {
usersLoaded = usersLoaded + 1
}
if(usersLoaded > 1) {
unsubscribe;
}
});
Here's a full working REPL:
→ https://svelte.dev/repl/95277204f8714b4b8d7f72b51da45e67?version=3.35.0
You might try Svelte's get. A subscription is meant for situations where you need to react to changes; it's a long-term relationship. If you just need the current value of the store, get is the way to go.
Occasionally, you may need to retrieve the value of a store to which you're not subscribed. get allows you to do so.
import { get } from 'svelte/store';
const value = get(store);
I had to use unsubscribe() instead of unsubscribe 🤡
Here's the final working REPL with some improvements:
https://svelte.dev/repl/95277204f8714b4b8d7f72b51da45e67?version=3.35.0
You can use auto subscribe: $user which will also auto unsubscribe.
Some more details in the docs.
Example:
let user1 = null;
$: if ($user?.first_name && !user1) {
user1 = $user.first_name;
console.log('first user', $user.first_name);
}
And you do not really need a writable store here. You can use a readable and use the set method to handle the fetch.
Something like:
const user = readable(defaultUser, set => {
.... fetch the data ....
.... set(data)
}
By the way: This is already async code and you can use set(data) to store the fetch result.
Updated: 04 Jan 2023
Best way to unsubscribe is using onDestroy Svelte's hook
import { onDestroy } from "svelte"
const subcriber = page.subscribe((newPage) => handleChangePage(newPage.params.id))
onDestroy(subcriber)

Returning a value from an Async Function. AWS/React

I'm trying to build a component that retrieves a full list of users from Amazon AWS/Amplify, and displays said results in a table via a map function. All good so far.
However, for the 4th column, I need to call a second function to check if the user is part of any groups. I've tested the function as a button/onClick event - and it works (console.logging the output). But calling it directly when rendering the table data doesn't return anything.
Here is what I've included in my return statement (within the map function)
<td>={getUserGroups(user.email)}</td>
Which then calls this function:
const getUserGroups = async (user) => {
const userGroup = await cognitoIdentityServiceProvider.adminListGroupsForUser(
{
UserPoolId: '**Removed**',
Username: user,
},
(err, data) => {
if (!data.Groups.length) {
return 'No';
} else {
return 'Yes';
}
}
);
};
Can anyone advise? Many thanks in advance if so!
Because you should never do that! Check this React doc for better understanding of how and where you should make AJAX calls.
There are multiple ways, how you can solve your issue. For instance, add user groups (or whatever you need to get from the backend) as a state, and then call the backend and then update that state with a response and then React will re-render your component accordingly.
Example with hooks, but it's just to explain the idea:
const [groups, setGroups] = useState(null); // here you will keep what "await cognitoIdentityServiceProvider.adminListGroupsForUser()" returns
useEffect(() => {}, [
// here you will call the backend and when you have the response
// you set it as a state for this component
setGroups(/* data from response */);
]);
And your component (column, whatever) should use groups:
<td>{/* here you will do whatever you need to do with groups */}</td>
For class components you will use lifecycle methods to achieve this (it's all in the documentation - link above).

Callback not called in database .on method

I'm using react-native-firebase package, react-native and redux.
When I'm trying to initialize data by fetching tasks from firebase database. I'm calling async redux action from my react component's componentDidMount() method.
componentDidMount() {
let uid = null;
if (this.props.sessionState.authUser) {
uid = this.props.sessionState.authUser.uid;
}
this.props.fetchToDos(uid);
}
And everything works fine on the first build of React Native app, but when I save and reload, for some reason the callback of my db call is not called and it keeps not being called until I completely rebuild my app. Again it worked fine on the first load of an app.
Here is the call to database:
export const fetchToDos = (uid) => async dispatch => {
var userId = firebase.auth().currentUser.uid;
database.ref().child('users/' + userId + '/tasks/').on('value', snapshot => {
console.log('INSIDE');
dispatch({
type: 'FETCH_TASKS',
payload: snapshot.val()
});
})
};
I'm porting my app from the web and this code works perfectly fine with my web app.
This Github issue seems like your problem, I think you should give it a look. Good luck!

Nuxt.js Loading data serverside with nuxtServerInit and Vuex

Currently i am working on storing data for a job opening application.
For the backend i use Laravel and for the frontend i use Nuxt.js
I am new to Nuxt, so i'm kinda stuck on the following issue.
I have a page for creating a new job opening called new-job.vue. I also created a store called jobs.js for handling the states.
On new-job.vue i have a form with data that has to be rendered in a list before the form starts.Like a list of all countries etc.. in order for me to select them in the form.
At this point i'm using asyncData within the export default on new-job.vue:
<script>
export default {
asyncData(context) {
return context.app.$axios
.$get('jobs/create')
.then(data => {
//context.store.dispatch('jobs/getTypes', data.types)
context.store.dispatch('jobs/getPlatforms', data.platforms)
context.store.dispatch('jobs/getCountries', data.countries)data.branches)
// return {
// loadedPost: { ...data, id: context.params.postId }
// }composer required barr
})
.catch(e => context.error(e))
},
computed: {
types () { return this.$store.state.jobs.types },
platforms () { return this.$store.state.jobs.platforms },
countries () { return this.$store.state.jobs.countries },
},
}
The asyncData method works and the lists of types, platforms and countries are getting filled with data from the database and the state from the Vuex store gets updated. .Only the data is being rendered on the client side.
I prefer this data to be loaded server side, so i was looking at nuxtServerInit. Only can someone explain to me how i can make this happen.
I placed an async call inside the export default of new-job.vue:
async nuxtServerInit ({ commit, state }, { app }) {
let res = await axios.get(`jobs/create`)
console.log(res)
commit('setPlatforms', res.data.platforms)
commit('setTypes', res.data.types)
commit('setCountries', res.data.countries)
},
I created the commits in the mutations of the jobs.store, but the states are not being updated.
What am i doing wrong and/or what am i missing?
Or maybe another question, is nuxtServerInit the way to go? Or is loading these lists of data on the clientside not a big deal?
UPDATE:
I use modules mode for the store, so i created a store called jobs.js. Inside this file i tried to call nuxtServerInit as well, but i didn't get any response.
nuxtServerInit(vuexContext, context) {
return context.app.$axios
.$get('jobs/create')
.then(data => {
console.log(data)
})
.catch(e => context.error(e))
},
From nuxtServerInit API reference in Nuxt.js documentation:
If the action nuxtServerInit is defined in the store, Nuxt.js will call it with the context (only from the server-side).
In other words, it is a reserved store action available only in store/index.js file and if defined will be called on server-side before rendering requested routes.
Only asyncData and fetch methods are available within pages.

Categories