Awkward property access .default when using default export folder structure
Hey,
I've come across a situation where I'm required to access the API object in a mutation using .default.
Relevant code: In my store.ts file, I'm exporting the mutation as a default export. However, I find the usage of .default in the useMutation hook to be a bit awkward. I'm wondering if there's a way around this, or if there's a different recommended approach for accessing the API object in a mutation. Folder structure: Just a mild annoyance, when trying to keep things neat.
Relevant code: In my store.ts file, I'm exporting the mutation as a default export. However, I find the usage of .default in the useMutation hook to be a bit awkward. I'm wondering if there's a way around this, or if there's a different recommended approach for accessing the API object in a mutation. Folder structure: Just a mild annoyance, when trying to keep things neat.
6 Replies
This is working as expected.
If you want the mutation to have a reference
api.users.store
, you need to put the store
mutation into the users.ts
file.Yeah. That's actually usually how i had my mutations and queries structured, but I was mainly curious if there is a way around that, since i wanna keep my functions on a per file basis within a folder that is named after a given table.
But im assuming this is just a limitation to how typescript works or something?
There a few reasons why i prefer this approach:
1. I make objects containing validators for my invidual schemas, so when i build functions i can import that object and using a spread operator pick and choose the values i wanna use for the args.
2. It's a bit nicer as the project grows, to just have functions contained in their own files, specially for functions that are large.
So i'm fine with the tradeoff being that i have to use the .default to grab the actual function off the api object.
Example of what i mean:
This is how the
api
object is set up (and we do need to disambiguate between api.users.store
and api.users.store.default
)
You can also have a single named exported function in a file. Totally up to you.Yeah although that would result in
api.users.store.store
if im not misunderstanding, in the case i exported a single named function called store from the store.ts file that lives in my users folders (with all other related functions)
Revisiting this. Is convex gonna allow for more control here at some point?
I'd love to ask how you handle folder structure for a large project like the convex dashboard which i assume is using convex?
We are trying to come up with a good solid, scalable folder structure. And keep hitting some awkward situation with how the api object gets generated, and how we wish to structure our backend.
It's mostly an annoyance in how we end up having to access functions on the api object.
If we choose to seperate our query / mutations functions into folders and or individual files.
We end up having to access that with either .default if we default export it, or the name of a named export from that file.
So say we have /convex/video/mutations/create.ts
we would have to do:
api.video.mutations.create.create
or api.video.mutations.create.default
It's kind of difficult finding a good folder structure for a large project, that plays well with how the api is generated imowe used to recommend default exports; these days I would say we pretty strongly recommend against it
most teams settle on something like /convex/bar/baz.ts where
baz.ts
contains a bunch of queries/mutations around managing baz-es
and then the calls are always api.bar.baz.getAll
or whatever
default exports end up problematic for a few reasons. (1) "default" is a kind of lame identifier and it takes up space without adding value; (2) normally, it ends up feeling more useful to put all the queries/mutations for a certain model together in the same file. that way they can share helper functions, type definitions, what-have-you
actions are sometimes in this same file, if they're very specific to that model (table); but some teams keep actions somewhere, both b/c they're more likely to need to "use node";
, and they often map workflows over many different models. so it doesn't feel right to attach them to one specific module with queries/mutations
in your case, my general advice would be this
api.video.mutations.create.create
that should probably just be
api.video.create
and you keep queries/mutations about videos togetherThanks a lot Jamie.
So to confirm, splitting functions into its own files is not really supported, without some extra property being added to the dot notation, in order to index it on the api object?