Build Fullstack Apps in Record Time with Blitz.js

Rate this content
Bookmark

Blitz.js is the Fullstack React Framework. It's heavily inspired Ru on Rails and is focused on making you as productive as possible. It's built on Next.js and adds all the missing pieces you need for building a fullstack app with a database. By far the biggest innovation of Blitz is the new "Zero-API" data layer that abstracts away the API so you don't have to mess with REST or GraphQL APIs!

Simon will introduce all the important parts & guide you through getting started with Blitz, so you'll know if you might want to use it or not.

67 min
28 Oct, 2021

AI Generated Video Summary

Blitz.js is a full stack React framework that eliminates the need for REST or GraphQL. It provides a zero API data layer and allows developers to focus on building applications. Blitz offers features like React Suspense for asynchronous data loading, Prisma Studio for immediate updates, and a routes manifest for type-safe links. It also supports writing to the database through mutations and provides default caching with React Query.

1. Introduction to Blitz.js

Short description:

My name is Simon Knott, a developer tooling engineer. I work on tools to help you build better applications. I am the creator and developer of Queral, a job queuing solution for serverless deployments. I'm also a level two maintainer of Blitz.js, a full stack React framework. Blitz is meant for building applications, not just websites. It's a batteries-included framework inspired by Ruby on Rails and built on Next.js. It features a zero API data layer abstraction that eliminates the need for REST or GraphQL. Today, we'll learn how to use Blitz by building a project and exploring its important features.

This is me. My name is Simon Knott. I'm a developer tooling engineer, which means I work on tools that help you build better applications and build your applications better. By day, I am the creator and developer of Queral. Queral is a wonderful tool, a job queuing solution for serverless deployments. I happen to really like it. I hope you like it. Maybe you'll use it someday.

And I'm also a level two maintainer of Blitz.js, which is the reason I'm here today. And let's talk about Blitz.js, which is the reason you are here today. Blitz is the website of Blitz. Blitz calls itself the full stack React framework. And there's a couple of things in there. What does that mean? React framework. Blitz is a framework that you can use to build applications using React. And the full stack means that it's not only about the front end part of the thing, which you'd, for example, find in create React app or in Next.js. But it deals with the full stack from the front end layer to the back end layer, including the database. And Blitz is really meant to build applications as opposed to websites or document-heavy sites. I like to make this distinction from time to time where there's these kinds of websites that are more suited to like static generators. They don't change a lot. Things where you'd use Jackal or Next.js or whatever. And then there's applications that have a lot of interactive things, maybe even a database. And Blitz is very much for that. And then on the website, it has this subtext here, which includes a lot of things that are helpful to know about Blitz. It says, Blitz is a batteries-included framework that's inspired by Ruby on Rails, is built on Next.js, and features a zero API data layer abstraction that eliminates the need for REST or GraphQL. There's a lot in here to unpack. So what does batteries-included framework mean? That means that Blitz will give you most of the things you need to build an application by default. It brings everything with it. It's inspired by Ruby on Rails, not in the sense that we try to recreate Ruby on Rails, but we are very... Well, Blitz is very... It tries to have the same productiveness, the same productivity that Ruby on Rails enabled back in the days, but with a more modern feature. It achieves that by being built on Next.js. A couple of months ago, in the beginning, Blitz was really a compiled to Next.js framework, so we took your Blitz.js code, and then we compiled that into a Next.js application. That's changed a bit. Blitz now has its own Next.js fork. But what still holds true is that Blitz really is an extension of Next.js, so to speak. And everything that works in Next.js will also work in Blitz. And then there's this last thing, which really is, I think, the main feature of Blitz really, which is the zero API data layer abstraction. That's what we'll see in a bit. And that zero API data layer abstraction allows you to create applications and work with data from the database without having to think about building APIs, rather than the rest for GraphQL. And eliminating the need for GraphQL obviously is a shot against Redwood, which is similar to Blitz.js, but takes a slightly different stance in using a lot of GraphQL or promoting the use of GraphQL. We have the zero API data layer, and I will show you what that is.

All right. I think the easiest way for us to learn how to use Blitz is to actually build a Blitz project. And the rough plan for today is so we have three hours together, right? And we'll roughly divided into three for the next 60 minutes, maybe 70, maybe 75. I will give you an introduction into Blitz.js. I will build, I will showcase how to build a prototype for a for a conference workshop sign up page and I will try to show you I will show you the most important features of Blitz that way. Then we'll take a short break just so you can refresh, get some water, get some fresh air. And then we'll go into breakout sessions and you will, in pairs of two or three or four people, we'll see.

2. Breakout Sessions and Creating a Blitz Project

Short description:

And then we'll go into breakout sessions to work on your own small Blitz applications. Afterwards, we'll come together as a group to discuss what you've built, experiences with Blitz, and answer further questions. Let's start creating our application by installing the Blitz CLI and creating a new Blitz project. The newly created project comes with TypeScript pre-installed and a variety of pre-configured files for a better development experience.

And then we'll go into breakout sessions and you will, in pairs of two or three or four people, we'll see. Work on your own small Blitz applications. We'll do that for roughly an hour, twenty or so. And I will go around and answer any questions that might pop up, help you with any problems you have. So the goal for that is for you to really get to grips with blitz and just try to use it. And a lot of the time, that is when you really learn what some tech feels like. And then afterwards, we'll come together again as a group and talk about what you've built, talk about experiences you've had with Blitz and answer further questions.

Okay? Cool. So, let's start creating our application. I hope this is big enough for you to see. If not, let me know. So, let me just go to my temp directory. To use Blitz, you can install the Blitz CLI. You do that by running npm install, save globally, and then Blitz. I won't do that because I already did it and it will take a while. But after you've done that, you have the Blitz CLI installed locally. And that says error. We're not in a Blitz project. But you will see the Blitz version, that I am currently on Blitz 0.41.1 which I think is the most current version. And now to create a new Blitz project, you can run Blitz new and then the name of your project. We'll call it React Advanced Workshops. And now it will do some magic. It will ask you a couple things. What package manager do you want to use? We will use npm. What form library do you want to use? You'll see why that matters in a bit. Let's just use the recommended one. And then it will generate a couple of files for us. And while it now installs npm dependencies, let's open this. No, let's not open that directory. Let's open the generated directory in vscode.

So, this is our newly created blitz project. And it has a couple files. Let's just quickly go through them because I think you can see some things from here. Let's go from the bottom. We have a types.ts file and a tsconfig.json. But as you can see, blitz by default comes with TypeScript pre-installed. Blitz really is TypeScript first. You can write everything with JavaScript if you want. But it will be a much better experience if you use TypeScript because TypeScript just makes it a lot more fun to work on things. Then there's a README with some blitz specific things in there. We'll just ignore that. Some package.json things. Then there's a jsconfig. We give you pre-configured js testing out of the box. A blitz configuration file if you use next.js. This might seem familiar. This is an extension of the next.config file. There's the blitzen file, again, something for TypeScript. Babel that is just used because we do have some Babel transformations. Pretier is pre-setup, ESLint is set up already, and then here's some environment files where you can place environment variables, for example, for local development.

3. Exploring Folders and Database Schema

Short description:

Then what's interesting is the DB folder and the app folder. The DB folder contains a schema.prismo file. Prisma is a database client that comes with Blitz by default. The app folder contains pre-generated files for the development server and the pre-generated page. The file-based routing allows for easy customization of pages. The default database schema includes tables for user, session, and token for authentication.

Then what's interesting is these folders up top, some test folder with some pre-generated utilities for you to test. Public folder, that is the same one that Next.js also have, just with sort of static files. And then the mailers and integrations folders, we can ignore those. Those are just two conventions on how to build mailing things.

And then the DB folder and the app folder, and those are the really interesting ones. Let's look into them. The DB folder contains a schema.prismo file. Prisma is a database client. That is developed in Berlin, I think. So, some of you said Berlin, if you want to go by the offices. And it's a really well done database client for JavaScript and TypeScript. And I think also Go and other languages nowadays. And we will get into how to use this database client later. But this is one of the best things about Blitz, that it comes with Prisma by default.

And then there's this app folder that contains a couple of things. And before we look into that, let's start our Blitz development server. We do that by running Blitz dev in the main directory, similar to how you would run Next Dev or something. This will start up a development server. And now if we open up Safari, we can go to localhost 3000. And we have this wonderful pre-generated page. This page lives in app slash pages slash index to TSX. If you've used Next before, you might recognize this. So this is file-based routing. If the file lives at index.tsx the pages folder, that means it will be available at the index route. If it's called workshops, it will be available at slash workshops. And in that you can see that it exports as default a React component. This is just some blitz special type for React components, but this could just well be some React component.

And if we want to change something about this, let's not put congrats here but congratulations. Let's save them on characters here. We see that this has auto reload or hot reloading or whatever that feature is called. So this is like the file that generates this page. And there's a couple other files, the 404 page, which is shown when you go to a not found page obviously, and that app and document file. We don't need to talk about that. You probably won't need to look into that today. And then there's a couple other things here. There's this core thing which contains some of the components you see, lots of pre-generated ones. And then this user's directory, which we will look into later. Ravi wrote it's fast refresh, I guess. Oh, yeah. I think it's called fast refresh. Thank you. And this is the general photo structure. What's important for now is that in the app folder, there's a pages folder. And in the pages folder, you can place new pages. Let's look into this database schema here. Bits by default comes with a schema for you that does some of the authentication things. So it has a user table, a session table and a token table. This just works with the pre-generated authentication logic that Blitz gives you. So you might have seen these buttons, sign up and log in. We'll just sign up, let's put in some email.

4. Building Workshop List and Creating API

Short description:

We want to build an application that shows a list of upcoming workshops and allows people to sign up. We'll add a new model called Workshop with fields for ID, name, date, and description. We'll use Prisma as our database client and generate dummy data using Prisma Studio. To display the workshops, we'll create a new page and define a function called workshops list. We'll return a header and an unordered list with dummy data. To get the data from the database, we'll need to create an API.

React advanced. Password is test, test, test. Create account. Nice. Now we have an account. And this logic is not something that's built into Blitz, but we just generate it for you. So, there's, like, some password changing or reset methods, and you can just change it if you want. But this is useful for today. And we won't need to look into this. But what we want to do is we want to build an application that shows a list of upcoming workshops, for example, at the React Advanced Conference, and that allows people to sign up for these workshops. So, we will add a new model called Workshop. We'll give it an ID. For now it's an integer. We'll mark that as an ID field and we'll auto increment it by default. We will give the Workshop a name, which is a string, and we'll maybe, this is GitHub Copilot speaking, we will give it a date, which is a date time. We will give it a, let's give it a description, which is a string, and I think that's it for the moment. And then what we do is we open up a terminal and run blitz Prisma generate. That's just something you need to run after you updated your schema. We'll talk about why you need to do that later. And just as a reminder here, Prisma comes pre bundled with Blitz. But if you want, you can swap that out for some entirely different database client. You can use whatever you want, but we at Blitz, we're big fans of Prisma. So that's why we bundle it. All right. And we want to show a list of these workshops. I think a good idea is to just put in some dummy data first. To do that, we can use the Prisma Studio. If we run that, it will open up a browser tab and have this very nice... Why doesn't it want that? Oh, I had that before. I think we need to run Blitz Prisma migrate. Maybe. Why is that still a thing? DB push, is that a thing? Yes, that works better. Apparently in AT, I need to do some more digging into how Prisma actually works, so you always forget what commands to run in what order. And this is like a very easy to use database UI. And we see in the user table, we have that user that we created, react-advanced-assignment-knob.de user. Let's add a new workshop. Add record, give it a name, uh, let's intro, the date is 2021, 10, 28, 16, no, at 15 UTC, the description is, let's learn everything there is to, and save the record. And let's just add another one. I think there is one on, uh, editor experiences, also today. Let's just have an hour later, this also seems interesting, just so we have to, to rise. Didn't it put anything here? Okay. And now we want to, we want to display these values. And what we'll do for that is we'll create a new page in the pages folder, we'll call it workshops.ts.tsx because we want to use jsx apparently, obviously, and we will define a function called workshops list. We'll export it as default and in that workshops list we'll return, let's call this add a main thing as a header and then an unordered list just with some dummy data in here and then add it to our experience. And now if we open up a local host slash workshops, we will see a wonderful list of workshops, but obviously we want to get this like we don't want to have this um we don't want to have this hard-coded but we want to get this from some database from our database. And now think a second what would you do to to build this with for example NexJS or with anything else. You would most probably uh think about creating some kind of an API. Maybe not in this workshop's case. This is the site that we're currently building could well be some statically generated document but imagine we're building a more complicated application here. So we'd most probably create some kind of an API.

5. Choosing API Architecture

Short description:

There are several questions you need to answer when deciding on the API architecture for your application. REST, GraphQL, and RPC are some options to consider. While these choices may seem important, in most cases, the choice between REST and GraphQL doesn't significantly impact the user experience. However, it is still a crucial decision to make.

And there's a couple questions you need to answer when you when you do that. Do you want to have a REST API? Do you use GraphQL? Maybe is it RPC? If you use REST, how are your routes called? What HTTP methods did you use? How does authentication work? And all these kinds of things that are really hard questions to think about, but if you think about the grand scheme of things and what that means for your application, it doesn't really matter a lot. For most applications, there will never be a customer that comes to you and says, oh, I love that you built this using GraphQL. It makes my experience so much better. That just won't happen. And in the end, whether you use REST or GraphQL, for the most cases, is not a big difference, but still, it's a big decision to make.

6. Fetching Data with Blitz

Short description:

And when Brandon Beyer, the original creator of Blitz, asked how data fetching would look if it was easy, Blitz provides a simple solution. By creating a magic folder named queries and defining a function to fetch data from the database, we can easily call this function from the frontend. Blitz automatically generates an API endpoint for the function, making it a zero API data layer. This allows developers to focus on building applications without worrying about the backend implementation.

And when Brandon Beyer, who's like the original creator of Blitz, when he first built Blitz, he asked this question of how would this look like? How would data fetching look like if it was easy? What is the easiest developer API we can have for that? And well, to fetch data, what do you do? You just call code. That's what you do. You just call some function. That's what you can do with Blitz. So let's do that.

We will go into this app folder, and we will create a new magic folder called queries. And it's important that it has this name because this is a magic name. I'll talk about that more later. In the queries folder, we'll create a file called getworkshops. The name doesn't really matter here. And in getworkshops, we can define a nice function called getworkshops. We'll export it as default. And in that function, we can just import a database from DB. This import from DB is just a shortcut to import db slash index.tsx. So if I put a slash here, you see that it has all the files in here, but we'll just import from DB. And then inside of getworkshops, we can do mdb.workshop.findmany. And we'll find, we'll just find all the workshops. We'll await the result and return it. The nice thing about Prisma is, and if you look at the result type of this, it will, does it say something nice? I think it says something nice. It will now return an array of workshops. That's the very nice thing about Prisma is that it gives you type safety really easily. And so now this is a function that gives you all workshops. And now, how do we call that from the front end? To be honest, it's really easy. We can just import getworkshops from Query slash getworkshops. And now you have a TypeScript function that you can just use. So what you could do is let's just do getworkshops. And like this returns a promise. And once we, once we have that, let's just console.log the results, just to show you that this works. So I think your development server just crashed because we didn't restart it after, after updating the Prisma schema. That's something we need to do because it needs to reload the Node.js files. And it can't do that for some reason because Prisma does some not super Node conventional things. But now that's restarted, this should work. And if we look into the console, we can see that it contains the two arrays queried from the database.

Okay, so this seems very magic. How does this work? We have this function in queries slash get workshops.ts. That is just a very normal plain TypeScript function. It looks very normal. And we just import that in our React component, which can just call it. And what will happen is that this thing here only runs in the frontend, while this thing here only runs in the backend. So how does this magic work? Like you can just import a backend function and use it. But with Blitz, you can. So I told you that this query's name is magic. And the way this works is that Blitz will check your imports. And whenever it finds an import from a folder named queries, it will replace this import and instead write just some pseudocode here, async function, get workshops, return, fetch slash API slash query slash get workshops. And it will also automatically generate an API endpoint for this. So the way this works is that Blitz recognizes these imports and generates an API for you, right? It's an auto-generated RPC API, because it's pretty much a remote procedure call. And that is what Blitz means when it says zero API data layer. This is not zero API because there is no API, but because you don't need to care about it. Similar to how serverless is not about not having servers, but about not caring for servers, or not having to deal with them. All right.

7. Using React Suspense for Asynchronous Data Loading

Short description:

We can just call functions as normal TypeScript imports, enabling type checking. With Blitz, we use the use query hook from React query to fetch data from the API. React Suspense is a beautiful feature that allows components to suspend rendering until data is ready. It ensures a synchronous-looking code while handling asynchronous operations.

So, we have found that we have functions that we can just call. And the nice thing is because these are just normal TypeScript imports, our types work. That is a thing that I personally find to be the most beautiful about this 0API data layer design. Because in the code, this is just like normal function import, and that enables TypeScript to do all its normal type checking work. Normally with a REST API, you need to do some serious work to get some notion of type safety. With that, not at all.

Don't need to think about it. We know React, it can be a bit weird to work with promises inside of components, so we could do some standard user fact thing here and save that into some state. We won't do that, but instead we use the use query hook from Blitz. This is built upon React query, which you may have heard of. React query is a really great abstraction around querying APIs and let's just make use of it. That is a common theme you find at Blitz. We tend to, if we find a really good existing library, we tend to integrate it well, as opposed to rebuilding it ourselves.

Now, what we can do is we can write use query, get workshops, and I think we don't need to give it any parameters, but we put undefined in there, and then this will return an array of workshops. And as you can see again, this has the perfect TypeScript type. Now if we want to show this, let's just map over the workshops. So we have a list item where we put in the workshop name. Now if I save this, you will see that this works and it shows the right things. But once I reload this page, it will hopefully throw an error. Oh, it even catched the error. This threw an error. Okay, what is this? Let's read through that error, because it's really interesting. It says a React component suspended while rendering, but no fallback UI was specified. Add a suspend fallback component high in the tree to provide a loading indicator or placeholder to display. What does this mean? Maybe some of you have heard of React suspense. That's a new upcoming feature. So there is, there's been suspense for a while for loading, for loading components. But in an upcoming React version, there will be React suspense for data loading. And what is this suspense? It is one of the most beautiful things of React, in my opinion. So if we look at this code, this code looks very synchronized. We call use query, give it get workshops and it will immediately return an array of workshops. This code looks like this is there immediately. But in reality, calling the get workshops API, getting the data that takes a while, this is not a synchronous operation. You can see that by this function returning promise. So how does use query use get workshops and then get back a non-promise array of workshops? How does that work? That is where React Suspense comes in. So the way this works is react will try to render this function. It will go through this hook. And this hook will kick off this query. It will call the API, the generated API, try to get some workshops, and then we'll see, oh, shoot, I don't have data. I can't give anything back. I am not ready to render. And it will say, please stop React. I suspend. I am not ready yet. That is what use query says. It's implemented by use query, like throwing a special error, I think. But what you need to know is that use query can suspend rendering. It can say, please React, do not render this component yet. I am not ready yet. But I will tell you when I'm ready.

8. Building Details Page for Workshops

Short description:

And until I'm ready, please suspend. Please show a fallback. A React component suspended while rendering. But no fallback UI was specified. So it is suspended because use query didn't yet have data. We can add that by wrapping it into a suspense boundary. This is how you query data. Another cool feature is Prisma Studio, which allows for immediate updates. Use query has instances where it tries to poll for new data. You don't need to deal with live data, Use query will handle it. You can also set options for refreshing data. Now let's build a details page for workshops. We create a new page with a parameterized route and a function to display the details. The page will show 'hello, world' for now.

And until I'm ready, please suspend. Please show a fallback. And that is what React says. A React component suspended while rendering. But no fallback UI was specified. So it is suspended because use query didn't yet have data and what React tries to do is it tries to find the nearest suspense boundary that is the suspense fallback component. And we can add that by not exporting the workshops display, but by wrapping it into a suspense boundary. So you can do that by importing suspense from React and then adding a suspense boundary that has loading as the fallback. Why is this oh we need to assign that to some value. Yeah, let's just ignore this. And now what you see is that this works and it will show loading really for a second here while it loads from the backend. Cool. So that is how you query data. I want to show you another very cool feature. So this is Prisma Studio. Is this still working? Yes, it is. I will now change something in here. I will change this to editor experiences extravagant. Just to have another word with me in there. And now when I press save on the left side, nothing happens, right? But when I go into this thing and now I will click into it, you will see that it immediately updates. And what does this do? So use query does not do, like it doesn't have a live subscription to always get the newest value. But it tries to do some pseudo live value thing where it has a couple of instances or a couple of moments where it tries to poll for new data. For example, when I re-open this tab, because we want to have the feeling of live data without actually having to deal with the WebSocket stuff. So whenever a user comes in and reopens the tab, we automatically update the values in here. And that is something that you don't need to deal with. Use query will do that on its own. Another thing you can do is you can post it with options and say, I want to refetch this every 200 milliseconds or something. And then what you see here in the background is that this will kick off new refresh. And you call every 200 milliseconds. Or you can say that I want to do some other things. It's not important right now. All right. So, this is how we do queries. Now, let's build a details page for these workshops. So, we will add a new page. What we want to have is we want to go to localized workshops and then the idea of a workshop. And we want to see a details page for this workshop. And so, what we do for this is we want to create like a page at this route. So, we add a directory here in pages, called workshops. And then we add a new file. And we call that ID.tsx. And we put the ID into square brackets. Those square brackets mean that this is a parameter. This is like a parameterized route. And here, anything could go in here. One, two, three, or foo, or bar, or whatever. And in here, again, we write a function, called maybe workshop details. That will return hello, world, for now. And we will export that as default. Now, if we go to that site, we can see that we have hello, world.

9. Accessing Parameter and Showing Workshop Details

Short description:

Now we want to have access to the parameter and show workshop details. We'll use the getWorkshopSingular query with the ID parameter. We'll add a suspense boundary in the app file to handle the lack of an ID. If there's no workshop, we'll display 'not found'. If there's a workshop, we'll show the name, description, and date.

Now, what we wanna do is we wanna have access to what parameter this is. For that, we can import a special hook. Let's call that, what that hook is called use param. And we give that the name of the parameter we wanna refer to. And then we can also give it a return type. Which just makes sure that this has derived type. And let's just try if this works. Hello world ID, we go to some other ID, we see that we have a nice parameter here.

And we maybe also want to show actual workshop details. So we'll need to build another query. So we need to fetch the workshops details, right? So that's what we use another query for. We'll call that getWorkshopSingular. And let's just copy this thing here. You could rename it. And now this gets one parameter called ID. And then instead of finding many, we find a unique workshop where the ID is the ID that's being put in. And we will now use the query for Blitz again. So we'll import useQuery. We'll also import the queries or the query query slash kind of workshop. I know we pause. I think I should turn off Copilot. This is a bit disturbing. Pilot toggle off disabling globally for now. And we will put in the ID parameter here. This will now say that the type doesn't work. Because type only find is not assignable to type number. That happens because of some internal ways of how Next.js works. There may be instances where this component is rendered without having an ID available. And we'll just put some placeholder in there for now.

And what we see is that this again throws the same error. It says we don't have a suspense boundary. And now what we'll do instead of wrapping every single component with that suspense boundary, we'll just be lazy and go into this app file, which is the main wrapping component. And we'll add a central suspense boundary around here that will now work for every single page. I don't think this is something you should do on the actual application code because you should have different suspense boundaries that show actually useful stuff. But for now, this is fine. And so we'll get back here a workshop. This could be a workshop or it could be no. So let's do if there's no workshop, that's return not find. And if there's a workshop, let's actually show some nice things. Let's add h1 tag. Can we format this nicely? This has workshop.name. That's a paragraph that has a description and let's add a date field. What's the time? Time. Workshop.date. To isostring. So it will say not found for 1, 2, 1, 2, 3. But if we go to number 1, this works. And if we go to number 2, this works too. And if we go to number 3, that doesn't exist, it will say not found because it uses this here. It might happen a lot that you don't actually want to, that you have queries that could return nothing because these IDs could be nonsense.

10. Checking Workshop Existence

Short description:

We can check if the workshop exists in the get workshop query and throw a not found error if it doesn't. This allows us to focus on the happy path and avoid cluttering the component with unnecessary conditionals.

And because that is quite usual, and you wouldn't want to stay at the same page, but you'd expect people to redirect it to 404. We can do a nice thing here. Inside of a get workshop query, we can check if the workshop actually exists. And if there's no workshop, we will throw a new not found error. And if there's one, we'll return it. And this changes things because now, the return type of get workshop is always a workshop. If there's no workshop, it will not return, but it will throw a not found error. And in here, we also know that this now will never be null. We can return this logic here. And if you reload this, it will automatically redirect you to the 404 page. And what I really like about this is that you can think in the happy path, right? This component isn't cluttered with a lot of conditionals about what happens if the workshop doesn't exist, all these things. But it only includes the part that you actually want to think about the happy one. All right.

11. Building Links and Navigation

Short description:

We can create links in Blitz.js by wrapping elements with an anchor tag and using the link component. This allows for instant rendering and prefetching of assets, improving navigation speed. We'll explore more features of links later on.

And we have this works for number two. If we go to number three, we'll get a 404. Cool. Amazing. Whatever this was, that was interesting. Cool. So that is how we can build details page. And we'd likely also want to have links here, right? So let's go back to our workshops page. And let's wrap that list item with an anchor, and put in href to slash workshops plus workshop.id. And I think we also need to raise up the key for it here. And now we have links. Nice. What's interesting to see here, maybe you notice that if I press on here, it will reload the full page. And if you've worked with Next.js before, you know that that is not necessary at least with Next.js. And in Next.js you use the link component, the same components available with Plits. So if you wrap this anchor in a link component and move up these properties again, then you will have instant writing here. We will immediately show you all the data. And what's nice about this is that not only it doesn't do a full HTML reload, but that it also will automatically prefetch any assets it needs as soon as this link is rendered. So if we go to the index page and then open up the network tab, let's go to slash workshops. And you see that, where is it? Or maybe it already had it in cache, but as soon as this link is rendered, it would immediately prefetch this subsequent page to just make navigation smoother faster and whatnot. Right. So this is linking. There's another feature to links that I'd like to show you later on. But just keep that in mind. We'll get back to that. And if I forget it, please remind me that I showed it to you.

12. Adding Participants and Subscriptions

Short description:

Now we have a list of workshops and want people to be able to subscribe. We add a participants relation, a many-to-many relationship. We include participants in the query, show their emails, and display them in a list. We add a subscribe button and use mutations to write to the database.

All right. So now we have a list of workshops. We can navigate into it. And maybe we also want people to be able to subscribe to these workshops. So we will go back into our schema here. And we'll add a new relation. We'll see that we will add a participants array or participant's relation, which is a list of users. For every workshop, there's a list of participants. And for every user, there's a list of workshops. So this is a many-to-many relationship.

And we will stop our development server. We'll run Blitz, Prisma. Generate, no Blitz Prisma DB push to update the database. And we will restart our development server. And now what we can do is let's start by showing the participants. So, I think we need to do here, let's just check if this is true, we'll need to say include and we want to include participants. Oh, it is automatically reloaded. Prisma, that's nice. I was just thinking about sometimes you need to restart the TypeScript development server if you make changes to your schema.prisma because TypeScript needs to re-index their generated typings, but that wasn't the case now. Which I am very fine with. And maybe we don't want to include everything about participants but only will include selected fields, namely, let's just keep it at that name. I think the name is totally fine for what we want to do. So, what you can now see is that this returns a promise of an array of workshops and then an array of participant objects which have a name. I think there's no names in our database, so let's use emails instead.

And in our workshops file, we can add a... Oh, no, that's a workshops list. In our workshop details file, we'll add a header, participants. We'll add an unordered list in there and for every... Oh, wait, I added... I changed the wrong query. I didn't need to change this query, but I need to change the GetWorkshop query. So, for every participant we show a list item that has the participant's email and those id we'll just also use the participant's email. Why doesn't this... oh, it's called key, not id. This is now saying undefined is not an object. Oh, no, it's working. All right. All right, we have a list of participants. The question is how do you actually subscribe to an event? And for that, let's add another button. That's not an upper button but a first button. Let's give it the title subscribe. And when that button is clicked, we'll just for the moment alert I want to subscribe. So this works. All right. We've talked about queries, right? Queries are for fetching data from the database. It's for reading. Now what we want to do is we want to write to the database. And for that, we can't use queries because queries are for reading. But we want to use so-called mutations. And they work very similar to queries.

13. Writing to the Database in Blitz

Short description:

To write to the database in Blitz, we create a magic folder called mutations and define an async function called subscribe to workshop. We update the workshop by connecting the participant with the user ID of the requesting browser. We use the context.session.authorize function to ensure the user is authorized. After calling the mutation, we update the data displayed by using the workshop meta.refetch function. This is how you write to the database in Blitz.

So instead of using this magic folder called queries, we'll create another magic folder called mutations. Instead of mutations, we'll create a file called subscribe to workshop. It is the workshops singular. And we will define an async function called subscribe to workshop. We'll export it as default. It will get a workshop ID as its parameter. And then we will again, as we know it, import database from DB and call db.workshop.update. We'll update workshop where the ID is the workshop ID we got. And we will write some data. We will update the participants and we'll connect the participant where the ID is. All right. What ID? We need to find a way to get the user ID of the requesting browser, or the requesting user. If we look at the main page, I think there's a user ID written here. My user ID is one. But we need to get the user ID of the user that is calling in. And for that, this mutation is always passed a second parameter. We'll get a type from blitz that shows what's in there. That parameter is called context. And under context, there's the session object. That session object contains information about the session of the client. For example, the user ID. And that user ID could be number or null. What you could do is say if there's no user ID, we'll just throw a new error. So unauthorized. Get out. But as always, there is a neater way. What you can do is you can call context.session.authorize. And once you've done that, you see that the type of this, this returns asserts this is authenticated session context. Once you've done that, you'll see that the type of user ID changes. The user ID after the call is a number. The user ID before the call is number on null. So this authorize is pretty cool. That's a nifty feature in TypeScript. By calling authorize, you know that this will be number. Because if this if the user is not authorized, if they don't have a user ID, then this call here will immediately throw an error. And now what we can do is we can just put in user ID here and we'll await that. And that's everything we need to do to add some value to that workshop. So now what we can do instead of calling window.alert, we can import from mutations, our subscribe to workshop mutation and we can, I think you need, nowadays you need to use the invoke helper function from let's, you can say invoke the subscribe to workshop mutation with the parameter id and wait that and then oh I guess that's it. Reload the page, we say subscribe and nothing will change but once we reload the page we see that there now is a participant. So why didn't anything change? Because the data that's shown here comes from this query and Blitz has no way of knowing that calling this mutation changed something about the value of this query. So what we need to do is we need to make sure that once this mutation was run that we update this thing here. And so we'll get the second parameter here which we'll call workshop meta. On our map we can say workshop meta.refetch, please. Please update this value and now if we open up our studio, it's still running. Yes, it is running localhost 5555 and we feels can we, I think we need to reload studio because we changed something up the data schema. We can remove this participant, just check things again. And now if we open this press subscribe, we see that things update. All right. So that is how you write to the database in Blitz. Similar to the use query helper, there's also a use mutation helper.

14. Overview of Blitz Features

Short description:

You can use it if you want. It gives you some nice things, but it's not strictly necessary. So that's how we build a very, very basic workshops tracking application. I wanna show you this one other feature about links. We have the so-called routes manifest, a type-safe way of building links to other pages. Another thing is the Blitz repple, similar to Ruby on Rails console. You can use this to test your queries and debug things. Blitz install commands can be used to install libraries or set up projects with recipes. This is a rough overview of what Blitz can do, focusing on the zero API data layer.

You can use it if you want. It gives you some nice things, but it's not strictly necessary. All right. So that's how we build a very, very basic workshops tracking application in 40 minutes, I guess, 45 minutes. I promised you, I wanna show you this one other feature about links.

So take a look at this line 14 here, where we use the href, like a string-based link to another page. What might happen is that you change the route of a page and now your links don't work anymore. And there's no way for you to, or it's not super obvious that that broke something. And what we have in Blitz is we have the so-called routes manifest. You can import from Blitz, Blitz the route object, and on the route object, there will be functions that help you for every single page you have, for example, for a workshop details page. So what you can do is you can put into this href, instead of putting a string in here, you can say routes that workshop details, and now this will say to you, you didn't put an ID into here, and you will parse it, the workshop ID here. So this is like a type safe way of building links to other pages. I know this still works the very same way.

Yes. There is another thing that I'd like to show you about Blitz, which is the Blitz repple. I think you can, let me check, I don't remember how to open it to be honest. You open it using Blitz console, and what you can use this for, this is similar to Ruby on Rails console. You can use this to test, okay, why doesn't this, why doesn't it like this? Property session does not exist. Okay, let's just ignore it. You can use this to test your queries. You can, for example, do wait db.project.findMany, and then it will return, oh no, project db.workshop. We'll return all your projects, db.user, what we can do. We could do these things, or we could also call our queries. So for example, await getWorkshops, then that will test our queries. And this can be really helpful to working development so you can just use this to debug things.

Another thing is the Blitz install commands, which you can use to install some libraries or to set up some projects that we have recipes for. So for example, if you run Blitz install Tailwind, that will take a while because it's cloning the recipe. Tailwind. And it takes a while and it will set up some things so that we can use Tailwind. Tailwind. Telled you some things about what it will do. This will install all necessary dependencies and configure Tailwind. You can press enter to install dependencies. Then it will create some config files, write some style sheets. It will even update some of our existing files to add support for Tailwind. And then once we restart our development server, we will be able to style things using Tailwind. Let's reload this page. Oh, so if you see this already looks a bit different because Tailwind reverts all existing styling. But we could now, for example, say that this, what file are we in? We're in the ID file. That this had a one, should have the class name, background, green. So this is how Tailwind works. I always forget how to, or how these class names are called. Background color, BG, minus green, minus 500. And now we have a green background, wonderful. So you could use these Blitz recipes to really fast set up certain libraries or frameworks and tools that you might wanna use. Cool. So I think that is a rough overview of what Blitz can do. We've spent the most time on the zero API data layer because that is really the main differentiating factor with Blitz. That's why Blitz is amazing or why I like it. Alrighty.

15. Workshop Break and Caching

Short description:

During the workshop break, the speaker addresses the audience and invites questions about Blitz. They mention that React Query provides some default caching, storing query results in the browser's local storage to show stale data while loading. The speaker emphasizes the importance of this feature and welcomes further questions.

It's 15 past the mic, look. So ready to get back into the workshop. Don't know about you. It was good for me to have that short break. Before we get into record rooms, are there any questions you have right now about Blitz? Questions that I can answer? Is there any caching of the API database calls? I think there is some form of caching by default. Yes, React Query does some. But any complex caching would be done by yourself. I think what React Query for example does is it will store the result of the query inside browsers local storage, so that when the page is opened up again, then it will be able to use stale data to show something while it's loading. Which is quite nice to give at least a bit of perceived performance. I think it's very good to know. Good to know. Definitely. Any other questions?

Watch more workshops on topic

React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Featured WorkshopFree
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
React Advanced Conference 2021React Advanced Conference 2021
132 min
Concurrent Rendering Adventures in React 18
Featured WorkshopFree
With the release of React 18 we finally get the long awaited concurrent rendering. But how is that going to affect your application? What are the benefits of concurrent rendering in React? What do you need to do to switch to concurrent rendering when you upgrade to React 18? And what if you don’t want or can’t use concurrent rendering yet?

There are some behavior changes you need to be aware of! In this workshop we will cover all of those subjects and more.

Join me with your laptop in this interactive workshop. You will see how easy it is to switch to concurrent rendering in your React application. You will learn all about concurrent rendering, SuspenseList, the startTransition API and more.
React Summit Remote Edition 2021React Summit Remote Edition 2021
177 min
React Hooks Tips Only the Pros Know
Featured Workshop
The addition of the hooks API to React was quite a major change. Before hooks most components had to be class based. Now, with hooks, these are often much simpler functional components. Hooks can be really simple to use. Almost deceptively simple. Because there are still plenty of ways you can mess up with hooks. And it often turns out there are many ways where you can improve your components a better understanding of how each React hook can be used.You will learn all about the pros and cons of the various hooks. You will learn when to use useState() versus useReducer(). We will look at using useContext() efficiently. You will see when to use useLayoutEffect() and when useEffect() is better.
React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Featured WorkshopFree
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
React Advanced Conference 2021React Advanced Conference 2021
145 min
Web3 Workshop - Building Your First Dapp
Featured WorkshopFree
In this workshop, you'll learn how to build your first full stack dapp on the Ethereum blockchain, reading and writing data to the network, and connecting a front end application to the contract you've deployed. By the end of the workshop, you'll understand how to set up a full stack development environment, run a local node, and interact with any smart contract using React, HardHat, and Ethers.js.
React Summit 2023React Summit 2023
151 min
Designing Effective Tests With React Testing Library
Featured Workshop
React Testing Library is a great framework for React component tests because there are a lot of questions it answers for you, so you don’t need to worry about those questions. But that doesn’t mean testing is easy. There are still a lot of questions you have to figure out for yourself: How many component tests should you write vs end-to-end tests or lower-level unit tests? How can you test a certain line of code that is tricky to test? And what in the world are you supposed to do about that persistent act() warning?
In this three-hour workshop we’ll introduce React Testing Library along with a mental model for how to think about designing your component tests. This mental model will help you see how to test each bit of logic, whether or not to mock dependencies, and will help improve the design of your components. You’ll walk away with the tools, techniques, and principles you need to implement low-cost, high-value component tests.
Table of contents- The different kinds of React application tests, and where component tests fit in- A mental model for thinking about the inputs and outputs of the components you test- Options for selecting DOM elements to verify and interact with them- The value of mocks and why they shouldn’t be avoided- The challenges with asynchrony in RTL tests and how to handle them
Prerequisites- Familiarity with building applications with React- Basic experience writing automated tests with Jest or another unit testing framework- You do not need any experience with React Testing Library- Machine setup: Node LTS, Yarn

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Advanced Conference 2022React Advanced Conference 2022
25 min
A Guide to React Rendering Behavior
React is a library for "rendering" UI from components, but many users find themselves confused about how React rendering actually works. What do terms like "rendering", "reconciliation", "Fibers", and "committing" actually mean? When do renders happen? How does Context affect rendering, and how do libraries like Redux cause updates? In this talk, we'll clear up the confusion and provide a solid foundation for understanding when, why, and how React renders. We'll look at: - What "rendering" actually is - How React queues renders and the standard rendering behavior - How keys and component types are used in rendering - Techniques for optimizing render performance - How context usage affects rendering behavior| - How external libraries tie into React rendering
React Summit Remote Edition 2021React Summit Remote Edition 2021
33 min
Building Better Websites with Remix
Remix is a new web framework from the creators of React Router that helps you build better, faster websites through a solid understanding of web fundamentals. Remix takes care of the heavy lifting like server rendering, code splitting, prefetching, and navigation and leaves you with the fun part: building something awesome!
React Advanced Conference 2022React Advanced Conference 2022
30 min
Using useEffect Effectively
Can useEffect affect your codebase negatively? From fetching data to fighting with imperative APIs, side effects are one of the biggest sources of frustration in web app development. And let’s be honest, putting everything in useEffect hooks doesn’t help much. In this talk, we'll demystify the useEffect hook and get a better understanding of when (and when not) to use it, as well as discover how declarative effects can make effect management more maintainable in even the most complex React apps.
React Summit 2022React Summit 2022
20 min
Routing in React 18 and Beyond
Concurrent React and Server Components are changing the way we think about routing, rendering, and fetching in web applications. Next.js recently shared part of its vision to help developers adopt these new React features and take advantage of the benefits they unlock.In this talk, we’ll explore the past, present and future of routing in front-end applications and discuss how new features in React and Next.js can help us architect more performant and feature-rich applications.
React Advanced Conference 2021React Advanced Conference 2021
27 min
(Easier) Interactive Data Visualization in React
If you’re building a dashboard, analytics platform, or any web app where you need to give your users insight into their data, you need beautiful, custom, interactive data visualizations in your React app. But building visualizations hand with a low-level library like D3 can be a huge headache, involving lots of wheel-reinventing. In this talk, we’ll see how data viz development can get so much easier thanks to tools like Plot, a high-level dataviz library for quick & easy charting, and Observable, a reactive dataviz prototyping environment, both from the creator of D3. Through live coding examples we’ll explore how React refs let us delegate DOM manipulation for our data visualizations, and how Observable’s embedding functionality lets us easily repurpose community-built visualizations for our own data & use cases. By the end of this talk we’ll know how to get a beautiful, customized, interactive data visualization into our apps with a fraction of the time & effort!