Open markerikson opened 10 months ago
@antonofthewoods moved this to a new issue.
@AntonOfTheWoods yeah, the Redux core examples
folder is years out of date, and frankly we should just delete all of them.
I'm afraid the rest of your question isn't really clear enough to provide an answer. I don't know what errors you're running into with installs, and installing Redux Toolkit + React-Redux works the same way with CRA and Vite (just npm i @reduxjs/toolkit react-redux
, or whatever package manager you're using).
Actually, re-reading your comment, now I'm extra confused :) Are you talking about the RTK Query-specific examples
folder here? That's also probably somewhat outdated - I think some of them are still referring to the original alpha package.
Can you give more specifics about what you need to do and what problems you're running into?
@markerikson thanks for your quick reply (and amazing reactivity on everything redux!). I couldn't get any of the sandboxes to work on my machine (after manually going through and copy pasting all the contents of the individual files... because codesandbox wouldn't give it to me as a repo or archive) -> I am getting a Error: error:0308010C:digital envelope routines::unsupported
error an none of the interwebs fixen worked for me in the 15-20 minutes or so I spent trying to get it to work. The examples all seem to require --legacy-peer-deps
(at least with npm
), and even with that I get constant:
anton@zub:~/dev/tmp/redux-toolkit/examples/query/react/basic$ npm run start
> @examples-query-react/basic@1.0.0 start
> react-scripts start
Failed to compile.
Cannot find module 'acorn'
Require stack:
- /home/anton/dev/tmp/redux-toolkit/node_modules/acorn-import-assertions/lib/index.js
- /home/anton/dev/tmp/redux-toolkit/node_modules/webpack/lib/javascript/JavascriptParser.js
- /home/anton/dev/tmp/redux-toolkit/node_modules/webpack/lib/javascript/JavascriptModulesPlugin.js
- /home/anton/dev/tmp/redux-toolkit/node_modules/webpack/lib/WebpackOptionsApply.js
- /home/anton/dev/tmp/redux-toolkit/node_modules/webpack/lib/webpack.js
- /home/anton/dev/tmp/redux-toolkit/node_modules/webpack/lib/index.js
- /home/anton/dev/tmp/redux-toolkit/node_modules/react-scripts/scripts/start.js
npm ERR! Lifecycle script `start` failed with error:
npm ERR! Error: command failed
npm ERR! in workspace: @examples-query-react/basic@1.0.0
npm ERR! at location: /home/anton/dev/tmp/redux-toolkit/examples/query/react/basic
Trying to install it in node_modules
or globally does nothing. I guess there is a small chance it's related to me using asdf
node
but I've never had an issue with vite
(or anything else to do with node
, python
or elixir
related to asdf
).
In terms of what I need to do - basically I am migrating a part of my app that has been using a local db (wasm sqlite) as the source of truth with a second level of RTK
caching to putting the source of truth from a REST api and so RTKQuery
. Previously I just passed the store via the inferno
context (extremely similar to plain react class context stuff if I understand correctly) and had the cache available. I don't really need or want subscriptions at this level, there are so many objects it would probably kill performance, explode memory or both. There are other things that can force a refresh if needed. I still want RTK because in other parts of the app I am using normal function components and I want/need all the normal behaviour.
If I do
const { data: knownWords } = await this.context.store.dispatch(knownWordsApi.endpoints.getKnownWords.initiate(""));
It looks like I'm able to get the data though I'm picking this is not going to scale much above my simple tests. If I try and refer to the state like I did before (via this.context.store.getState().knownWords
) then I get some weird kind of service object rather than the object/dict I had before.
There may be some way to get it to do what I need but I haven't been able to work it out yet. If I try and do the
const result = api.endpoints.getKnownWords.select("")(state)
const { data, isSuccess, isError, error } = result
Then I just get lots of undefined
and both isSuccess
and isError
are false
. For some reason it also forces me to put an arg for the select
even though it doesn't need one (and the example doesn't have one).
Typically in this sort of case I like to start from an official example that works and then just push it towards what I want to do, then adapt for my actual projects. Here I have been unable to use that method! Thanks again for all your help.
@AntonOfTheWoods I do think it might help to take a step back and separate out the different topics and concerns you've listed :)
The example project build errors are annoying, but ultimately irrelevant to the larger goal of trying to get this working in your app. One thing to try there would be either updating the examples to "react-scripts": "^5"
and see if that helps the install steps, or creating a new Vite project with our Redux template, and then copy over the example source code into that project.
Per the usage questions:
dispatch(someEndpoint.initiate())
and store.getState()
are two very different steps. dispatch(initiate())
is dispatching a standard RTK async thunk to make the request and fill in the cache entry. store.getState()
is getting the current overall store root state.
There shouldn't be any kind of a "service object" in the RTK Query section of the store state. It would be a plain JS object containing the cache data for the API slice, like {queries: {}, mutations: {}}
.
I'm not sure what you mean by "this isn't going to scale for my app". Can you clarify that? Per https://redux-toolkit.js.org/rtk-query/usage/usage-without-react-hooks , that is how you'd use the plain RTK Query API without making use of React hooks.
Yes, api.endpoints.someEndpoint.select()
requires some argument as the cache key. If you supply no argument, the cache key is undefined
. Whatever cache key you supply has to exactly match what you passed into the initiate()
thunk, because they both use the same logic to find the relevant cache entry.
Finally, note that the cache entries have a status field in them, but some of the derived values that get returned from the React hooks do not exist in the cache entry itself, so you may be trying to read fields that don't exist in the cache entry.
The example project build errors are annoying, but ultimately irrelevant to the larger goal of trying to get this working in your app. One thing to try there would be either updating the examples to
"react-scripts": "^5"
and see if that helps the install steps, or creating a new Vite project with our Redux template, and then copy over the example source code into that project.
Yeah, that's always possible, but we are now a major version up, and I don't see anywhere in the docs "you can safely assume our code will always be valid, no matter how many major versions of redux we iterate through". As I don't know how things are supposed to work, blindly assuming copy/pasting old code will work exactly the same way as new releases to try and learn seems a little risky...
Per the usage questions:
dispatch(someEndpoint.initiate())
andstore.getState()
are two very different steps.dispatch(initiate())
is dispatching a standard RTK async thunk to make the request and fill in the cache entry.store.getState()
is getting the current overall store root state.
Yeah, this is where things get a little murky for me... I get RTK and RTK Query are just opinionated layers on top of Redux but not so much what the public APIs are supposed to look like. Your comments below are starting to make things clearer though!
There shouldn't be any kind of a "service object" in the RTK Query section of the store state. It would be a plain JS object containing the cache data for the API slice, like
{queries: {}, mutations: {}}
.
Ok, I was calling that a "service object". With my non RTK Query code that is the particular state dictionary I'm interested in directly. I was erroneously assuming that's what I should expect from RTK Query also -> it appears I should be expecting to interact with the "low level" stuff, rather than what I actually care about (actual values).
I'm not sure what you mean by "this isn't going to scale for my app". Can you clarify that? Per https://redux-toolkit.js.org/rtk-query/usage/usage-without-react-hooks , that is how you'd use the plain RTK Query API without making use of React hooks.
So 30k+ subscriptions per page is fine (on an iphone with their stupid memory limits)? I can have 30k+ words on a page (each word has a multi-level html fragment), and each word would need a subscription. I should obviously test this out first rather than ask though!
Yes,
api.endpoints.someEndpoint.select()
requires some argument as the cache key. If you supply no argument, the cache key isundefined
. Whatever cache key you supply has to exactly match what you passed into theinitiate()
thunk, because they both use the same logic to find the relevant cache entry.
For this particular usecase I'm mainly interested in getting a single result set of lots of items (a set of words with, say, 0 to 10k entries) that I devalidate every now and then for various reasons.
I may be abusing the system a bit with how I'm using though...
@AntonOfTheWoods part of my point is that you're listing several different kinds of problems, some of which are very irrelevant to your ultimate goal of getting RTK Query working in your app. That feels like a distraction overall.
So 30k+ subscriptions per page is fine
No, this seems like it would be extremely bad for perf.
Even in a desktop app, having thousands of subscribed components on screen at once is bad. (I talked to Slack devs earlier this year, and they had 20K connected components on screen, and were having to go to incredibly outlandish lengths to keep the app performant.)
What is your app doing that you feel like you would need 30K subscriptions to the store?
I think, based on your description, that what you really want is one component asking for that data and passing the values down as props to all the nested children, but I'd need more details on the actual app itself.
but tbh I'm kind of lost at this point in the discussion :)
My main recommendation would be to read through https://redux-toolkit.js.org/rtk-query/usage/usage-without-react-hooks and see what questions you have after that.
Going through this right now and 100% agree that the docs, whilst a good starting point, are simply incomplete and fail to tell you how to fully perform a query without react hooks. I think they assume familiarity with redux and performing such operations with redux without react hooks more generally.
@rwilliams3088 what specifically would you expect to see in that docs page?
are simply incomplete and fail to tell you how to fully perform a query without react hooks
Not sure I understand this comment. https://redux-toolkit.js.org/rtk-query/usage/usage-without-react-hooks shows const promise = dispatch(api.endpoints.getPosts.initiate())
, which is the key piece of info you need to know to trigger a fetch.
I think they assume familiarity with redux
Yes, that's very much the case. We have to make assumptions so we don't end up repeating the same explanations all across the docs, so there's no reason to explain Redux basics like "dispatching" and store.getState()
in an RTKQ usage guide page.
@markerikson I would expect a full example. Which means not simply issuing the request, but how to receive the results. At minimum, detail the whole process and provide links to the relevant doc so that one has everything needed to put together a solution.
In my case, RTK Query is the only thing that I use Redux for - so the doc in question is rather frustrating to me as someone not immersed in the redux ecosystem.
@rwilliams3088 : we can try to add some more examples, but at the same time: it sounds like you're expecting this docs page to explain core Redux concepts, and that is not the point or goal of that particular docs page. Each page has a specific purpose.
If you want to understand those core concepts, our primary tutorials are in the core Redux docs site:
In this particular case, dispatch(api.endpoints.getPosts.initiate())
returns a promise for the data you've asked for, so const data = await dispatch(api.endpoints.getPosts.initiate())
should be the starting piece that you need. (The snippet shows const promise = dispatch()
to clarify that the promise has an extra refetch
method attached, which is not something you'd normally see attached to a promise.)
If awaiting the promise was sufficient to get the results, then the doc would indeed be sufficient. However, what it actually returns is an object with { status: "pending", ... }
- so awaiting the promise does nothing to get the results.
Additionally, the example code doesn't work with typescript. I have had to cast things as any
for now which is really undesirable.
However, what it actually returns is an object with { status: "pending", ... } - so awaiting the promise does nothing to get the results.
That should not happen and I'd consider that a bug. Can you create a reproduction?
Generally, "outside of React" is a bit of a problem: it works different in Vanilla than it does in Angular than it does in Vue than int does in Svelte than it does in Solid. Can you make it work in all of them? Sure. Do we know all of those? Nope :/
And that's ignoring that "Vanilla JS" is just a description for 200 more completely different approaches, including other frameworks like Lit.
That's a fair point. Which is why I'd like the example to at least talk through the whole process with a reference link or two so I can compose my own solution with my tech stack.
It would be troublesome to try to take everything I'm doing right now and turn that into a small reproduction (I'm implementing a feature flags server with Action Cable + AWS + Redis to automatically broadcast changes down to React clients and have them auto-update accordingly; lots of parts). I'm implementing a REST service with RTK Query in parallel to the Action Cable LIVE service, and I wanted to speed-up the page initialization by using the REST service to lookup a particular feature-flag value.
That said, I will try to find time to create a minimal reproduction as I am able. Just not sure when I'll have some down time to work on it offhand.
It looks like the initiate
docs are missing a key bit of info - you must unwrap
the query action creator result to get the response (or error). For example:
const result = dispatch(api.endpoints.listItems.initiate());
const items = await result.unwrap();
The createAsyncThunk
docs describe this API well.
You do not have to unwrap
, it's just a convenience thing.
The promise will always resolve to either a success or a rejection action, so you can just as well look at the .payload
or .error
properties of that returned object.
note that initiate actually wraps the promise, so instead of getting the action you get an object that either looks like { data } or { error }