Remix Fundamentals

Mutations Q&A

Kent C. Dodds

Kent C. Dodds

Professional Trainer
Remix Fundamentals

Check out a free preview of the full Remix Fundamentals course

The "Mutations Q&A" Lesson is part of the full, Remix Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

Kent answers student questions, including if anything needs to be done in the action loader to respond to actions and possible strategies for client-side validation. A demonstration of implementing error handling for the mutations extra credit is also provided in this segment.


Transcript from the "Mutations Q&A" Lesson

>> So if you gave the form an action to a specific URL, do you need to do anything inside the action loader to respond to that specified action case?
>> Yeah, so I think I understand the question, so you can say action API new post, okay. So if you wanted to do that then you'd go into your routes you'd make API and new-post.tsx.

And then you basically just take your action code that you have here, we just paste there. Bringing all the stuff which we, aw, the heck with it, let's just do it. Hopefully it works, okay, bring all this in. Okay, cool, so now we'll just get rid of that.

Yeah, this type of action isn't gonna be happening, you'd have to import it and all that, that's why we don't do this. But we can create a new post, and kaboom! Man, I messed something up, I don't know what went wrong. But that's basically how you would accomplish this, is you just make a separate file that has the same route as the action URL that you're providing.

And then yeah, all of your action code would just go there. Hopefully I understood that question, I might have misunderstood the question though.
>> So you moved the action code to its own file matching the action paths specified?
>> Yes.
>> I think I got it, yeah.
>> Exactly.

Cool, yes?
>> This isn't the final extra credit too but could you explain on the pic work so that you can type the create post action.
>> Yes, so right now create posts just accepts any, which is not very useful. What we really want is to have something like this, right?

That's what copilot wants us to do. But I don't wanna change this if I ever update my model to say, hey, now markdown is now content, or markdown is now whatever, right? So to both make it easier for me maintenance wise in the future, and also communicate what these actually is, this isn't just any old title, this is a post title, which is special.

Then I'm going to say, I want to pick a couple of properties off of the post type. And so, we actually have a type called Post from the prisma/client, the prisma/client gets updated as we update our model. And so we have all of the types for our model.

And so we want whoever is calling create posts to give us a post, but we don't have all of the properties. Like see, this is gonna complain because we're missing the ID and or the created at and various other properties. And so we don't want all of them, we just want the title, so I get marked down.

So we're going to use a special generic type from TypeScript called Pick, and it's going to say okay, what do you want me to pick types from? And so I wanna pick types from the post, and the types that I want are title, slug and markdown. Does that answer your question?

>> That's nicer than using partial.
>> Yeah, yeah, I think it's quite handy. There are some really amazing generics that are built into TypeScript. Recently, we got one called Awaited, or yeah, I think it's awaited, which is pretty rad. It allows you to unwrap a promise and my own utility for it for that, maybe it's called Await, I can't remember.

And we used to use that a lot until we got this handy piece of work, and now we don't need to use that as much. Okay, so now this is complaining, so I'm glad you asked that cuz I was part of the extra credit. We need to do a little bit of extra work, because remember how I said that this could be a form data entry value?

Well, it could, so we need to make sure that it's a string. So what we're going to do is say invariant. Invariant is this handy little utility, this package called tiny invariant that we're using. I think invariant as a library was made popular by the React project actually, that was the first time I saw that.

And I think they have their own implementation, but somebody built a tiny invariant, so it's a little smaller. But what this allows you to do is it's just a function where you give it some sort of predicate as the first argument, and then the second argument is the error message I want thrown if this predicate is not true, okay, so.

And then it integrates really nicely with TypeScript as well, so I can say type of title does not equal, or is equal to a string, and title must be a string. And then we'll do the same for our slug and our markdown. And so now, TypeScript knows that it can't get to this line, if any of these is not a string, and so that'll just be thrown.

And we could probably do some extra stuff if we wanted to give the user some helpful error message or something. But if we get to this point and those are not strings, then somebody is doing something nefarious, so I don't care about them anyway, so. So we're good, cool, any other questions?

>> Yeah, I got one, would maybe be strategy for doing like client side validation for form field?
>> Yeah, great question. In fact, somebody just asked me that this morning, so, or maybe it was last. First of all, I wanna call out something that actually is really awesome.

I can extract this to a function and say validate title, so where did that function go? Validate title, boom, and yeah, sure, we'll take FormDataEntryValue. And now, whatever this validation logic is, whether I could have a min and max and all that stuff, I can use that both in my server code and in my client code.

So that's neat, we can actually do code sharing across this boundary. Now of course, if you're doing accessing the database in here or something like that's not gonna fly, but you could make a resource route that does that. But yeah, so now we can use that, how do we use that?

For that sort of thing you aren't going to need to use state, to manage that, and so you just say, use state, titleError. And then yeah, your initial title error would probably be nothing, or I guess it'd be action data errors.title. And then from there, you would have to synchronize anytime the user submits the form, you'd probably use a use effect or you could probably put it in the.

Yeah, I probably use a use affect any time the action data changes, you'll go and call set title error to whatever the server sent back. And then as the user is typing you can set title.error to whatever. But this is the cool thing, and this is what we're gonna talk about in our next exercise, is that doing that does not make the rest of it more complicated, right?

It's just an additive thing to make the user experience a little bit better. We'll talk about that more.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now