RTKQ - Select data without hooks - javascript

I'm trying to select cached data from RTKQ without using the auto-generated query hook, but I'm having trouble understanding the docs
const result = api.endpoints.getPosts.select()(state)
const { data, status, error } = result
This is how the docs describe how to access the data, but I can't find any references on how to inject the state object "select()(state)".
I can't figure out how to access the data if I only call the select?
api.endpoints.getPosts.select()
Can someone explain me the difference between "select()" and "select()(state)"
Or what is the optimal solution to access the cached data from RTKQ?

The result of api.endpoints.getPosts.select() is a selector function for the result of using the "getPosts" endpoint without arguments.
Similarly, result of api.endpoints.getPosts.select({ page: 5 }) is a selector function for the result of using the "getPosts" endpoint the argument { page: 5 }.
A selector function is then called as selector(state) or passed into useSelector(selector).
If you write that altogether, you end up with api.endpoints.getPosts.select()(state).

#phry
Thank you for your answer! I'm not 100% sure I understood your answer. But it pointed me in a direction that enabled me to get the data.
I ended up creating a selector like the docs.
export const selectUser = (state) => userApi.endpoints.getUser.select()(state);
and in my function, I referenced it with getting the exported store from configureStore() method
const { data } = selectUser(store.getState());
But I'm not sure if this is the intended way to do it.

Related

Having promise response inside Vue template interpolation

I'm using Vue 2 and the composition API. My current component receives a prop from a parent and I render different data based on it, on the screen - the prop is called "result" and is of type Object, containing multiple info. I receive one "result" at a time, but multiple will be rendered - you can think of my "result" as a google search result - which means that the page will have multiple results.
The issue I have is that for one of the info inside "result", I need to call an asynchronous method and display its result, which is what I cannot accomplish.
Currently this is what I have:
<div>
{{ getBoardName(props.result.boardReference) }}
</div>
Method inside the script:
async function getBoardName(boardReference) {
var result = await entriesApi.getBoardName({
boardReference: boardReference,
});
return result;
}
It displays "[object Promise]", although if I console.log(result) right before returning it, it's just what I need, so it seems to me as if the interpolation doesn't actually wait for the promise result.
I've also tried using "then" inside the interpolation:
{{
getBoardName(props.result.boardReference).then((value) => {
return value;
})
}}
I was thinking about using a computed property but I am not sure how that would work, as the response I need from the method has to be connected to each result individually.
Please ask for further clarifications if needed.
As you thought, the interpolation does not actually wait for the result so this is why you have a Promise object.
Since you are using the composition API, what you can actually do is to use a reactive state (using the ref() function if you are waiting for a primitive type, which seems to be the case here, or the reactive() function for objects) and update the state within the onMounted() lifecycle hook.
setup(props, context) {
const boardGameName = ref("");
onMounted(async () => {
boardGameName.value = await getBoardName(props.result.boardReference);
});
async function getBoardName(boardReference) {
var result = await entriesApi.getBoardName({
boardReference: boardReference,
});
return result;
}
return {
boardGameName,
};
}
Since you are dealing with async data, you could add a loading state so you can show a spinner or something else until the data is available.
If your board reference changes over time, you could use a watcher to update your board game name.
Good luck with your project!

How to pass a function to React in State to sort your data based on multiple queries?

I am new to React and have a question regarding passing down functions in a state. I have a couple of 'sorting functions' in my util folder, which look like this:
export const sortColdestSummerCountries = (filteredCountries) => {
return filteredCountries.sort(
(a, b) => a.avsummertemp20802099 - b.avsummertemp20802099
);
};
and a few others:
sortHighestSummerTemp, sortLargestIncreaseHotDays, sortColdestSummerCountries, sortMostColdDays, sortWorstAffectedCountries which pretty much look similar. I use them to sort my data by users' request, and if I wrap sortHighestSummerTemp(filteredCountries) around my data, it works as a charm.
Now the issue: because I will have eventually 10+ filters, it makes sense to me to create a global state like this:
const onChangeQueryFilter = (e) => {
setQueryFilter(e.target.value);
};
Yet, upon trying queryFilter (filteredCountries) the terminal shows me "queryFilter is not a function" when I filter it? It's still the same sortHighestSummerTemp function right or what am I missing here? Do I summarize this problem correctly?
Hopefully it was clear and you understand what I am trying to do.
UPDATE:
I tried the following as well:
function sortBy(filteredCountries, sortKey) {
return [...filteredCountries].sort((a, b) => a[sortKey] - b[sortKey]);
}
// the queryFilter responds to the key, "filteredCountries.avsummertemp20802099" for example which passes to [sortKey].
const [queryFilter, setQueryFilter] = useState(filteredCountries.avsummertemp20802099);
const filteredData = sortBy(filteredCountries, queryFilter);
This does not work either, it still shows the old data (filteredCountries) but the filtering doesn't happen, the data isn't sorted. Does someone have a clue what I am doing wrong? Is it something in the sorting method? Or does someone have a better practice to pass a function to state?
Thank you a lot for being out here. :)

Vue Array converted to Proxy object

I'm new to Vue. While making this component I got stuck here.
I'm making an AJAX request to an API that returns an array using this code:
<script>
import axios from 'axios';
export default {
data() {
return {
tickets: [],
};
},
methods: {
getTickets() {
axios.get(url)
.then((response) => {
console.log(response.data) //[{}, {}, {}]
this.tickets = [...response.data]
console.log(this.tickets) //proxy object
})
},
},
created() {
this.getTickets();
}
};
</script>
The problem is, this.tickets gets set to a Proxy object instead of the Array I'm getting from the API.
What am I doing wrong here?
Items in data like your tickets are made into observable objects. This is to allow reactivity (automatically re-rendering the UI and other features). This is expected and the returned object should behave just like the array.
Check out the reactivity docs because you need to interact with arrays in a specific pattern or it will not update on the ui: https://v3.vuejs.org/guide/reactivity-fundamentals.html
If you do not want to have reactivity - maybe you never update tickets on the client and just want to display them - you can use Object.freeze() on response.data;
if you want reactive information use toRaw
https://vuejs.org/api/reactivity-advanced.html#toraw
const foo = {}
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo) // true
or use unref if you donot want ref wrapper around your info
https://vuejs.org/api/reactivity-utilities.html#unref
You can retrieve the Array response object from the returned Proxy by converting it to a JSON string and back into an Array like so:
console.log(JSON.parse(JSON.stringify(this.tickets)));
You're not doing anything wrong. You're just finding out some of the intricacies of using vue 3.
Mostly you can work with the proxied array-object just like you would with the original. However the docs do state:
The use of Proxy does introduce a new caveat to be aware of: the proxied object is not equal to the original object in terms of identity comparison (===).
Other operations that rely on strict equality comparisons can also be impacted, such as .includes() or .indexOf().
The advice in docs doesn't quite cover these cases yet. I found I could get .includes() to work when checking against Object.values(array). (thanks to #adamStarrh in the comments).
import { isProxy, toRaw } from 'vue';
let rawData = someData;
if (isProxy(someData)){
rawData = toRaw(someData)
}

Firebase firestore - Data must be an object, but it was: a custom Object object

I'm using Firestore in conjunction with realtime database in order to provide a user presence system for my application.
Update: article I followed
https://blog.campvanilla.com/firebase-firestore-guide-how-to-user-presence-online-offline-basics-66dc27f67802
In one of the methods I use this code here:
const usersRef = this.$fireStore.collection('users').doc(uid)
const whoIsOnlineRef = this.$fireDb.ref('.info/connected')
whoIsOnlineRef.on('value', (snapshot) => {
this.$fireDb.ref(`/status/${uid}`)
.onDisconnect()
.set('offline')
.then(() => {
usersRef.set({ online: true }, { merge: true })
this.$fireDb.ref(`/status/${uid}`).set('online')
})
})
The .set method, however, is giving me the error mentioned in the title and I can't quite understand why. I'm simply passing a javascript object to .set method and this should technically work.
Can you spot what is wrong with the code?
Looks like the reason why this wasn't working is that the code was running on the server in an SSR application.
I moved that very same logic to the browser and it started working nicely. I still don't see why this wouldn't work in the server as, at the end of the day I was still passing a simple js object to the .set() method.
Either way, there you have it

Gatsby Graphql Skip

I am trying to page through data in a react component in Gatsby from graphql via a button that increments state.count.
When I click the button the state.count is incremented but it is not passed to the query.
Any ideas what I am doing wrong?
pageUp=() => {
this.setState({count: this.state.count +2});
let skip=this.state.count
}
render() {
return (
<StaticQuery
query={graphql`
query ListingPageQuery ($skip:Int){
allMarkdownRemark(
limit:2
skip: $skip
)
{
...
}
}
`
}...
I see two issues in this code. First:
pageUp=() => {
let skip=this.state.count
}
The let statement causes the skip variable to be local to this function. It's not obvious from your question what causes it to be passed on to the GraphQL query, but if it's a member variable or something else, this statement shadows it and you're setting a purely local variable whose state will be lost.
Second:
this.setState({count: this.state.count +2});
let skip=this.state.count
State updates may be asynchronous, and the React documentation specifically advises against changing state the way you have it (there is a callback-based pattern that's more appropriate). The other consequence of this is that the state may not have actually updated when you get to the next line, so you're assigning count from the "old" state to the skip variable.
Looking at the Gatsby documentation, there is a specific note that StaticQuery does not support GraphQL variables, though browsing it doesn't suggest another path that does. (Every single example that shows potentially paginated data only shows the first page.)
You can't do that with Gatsby. GraphQL only happens at build-time not on the client. You'd want to grab all the content and then use JS to only show/skip what you want to show.
Looking at the Gatsby documentation, there is a specific note that StaticQuery does not support GraphQL variables, though browsing it doesn't suggest another path that does.
Moreover as David Maze said the StaticQuery doesn't support such variables. This wouldn't work in normal queries either because such variables need to be passed in via context.
https://next.gatsbyjs.org/docs/creating-and-modifying-pages/
Only if you pass it via context it's available in pageContext and as a variable in your queries (you normally use that for templates).
The setState() is asynchronous. The right way to capture the state is in a callback, also use the prev parameter to reference state inside a setState() :
this.setState(prev => ({
count: prev.count + 2
}), () => {
// here this.state.count was updated and safe to use
});
Reference: https://reactjs.org/docs/react-component.html#setstate

Categories

Resources