Astro for Fast Website Development

Microfrontend Cart Using Islands

Jason Lengstorf

Jason Lengstorf

Learn With Jason
Astro for Fast Website Development

Check out a free preview of the full Astro for Fast Website Development course

The "Microfrontend Cart Using Islands" Lesson is part of the full, Astro for Fast Website Development course featured in this preview video. Here's what you'd learn in this lesson:

Jason develops a React component for adding items to the cart and illustrates the concept of selective hydration using client directives. A student's question about utilizing nanostores to sustain state across multiple pages is also covered within this segment.


Transcript from the "Microfrontend Cart Using Islands" Lesson

>> We want to actually use this thing. Let's get these showing up. So I'm going to go back into shop.astro, And we're gonna import that Cart. And now I did it as a named export out of habit, I don't do default exports. So that's a preference, not a rule.

And I'm gonna grab that components and shop. Nope, cart is the one that we want. And then I'm gonna replace this with a Cart. Okay, so this looks like it's working. But it's not yet because we rendered this statically. So this is maybe the biggest gotta get used to it of Astro is that by default nothing is interactive.

So even though we've built this interactive component, by default, it's going to render whatever its standard state is. And then when we click buttons and stuff, it won't do anything. So to make this actually work, we're going to set it to client:only. And then because we're using multiple frameworks, we have to tell it which one we're using.

So we're saying client:only="solid-js". And now this is hydrated. This is actually a running JavaScript component. So the next thing we wanna do here is figure out a way to actually put some things into the cart. So we're gonna create a new component, and this one's gonna be built in React.

So we are going to say, add-to-cart.tsx. And this one is powered by React. So we're gonna override the TSConfig by putting in our own jsxImportSource and configuring to React. And that'll allow us to, Autocomplete is gonna work the way we expect, it's not gonna say you can't use class or className or things like that.

That's why this stuff is worth setting up. And one of the reasons that I do like TypeScript is that you can get those more useful errors. So next we want that addItemToCart out of the store. And then we can export a const called AddToCart and that one is going to return an item, or it's going to accept an item as a prop, and that item will be a ShopItem.

So that is coming out of our types that we already declared. Okay, let me make this bigger so that it's not hidden. So inside, we get a nice simple component. I'm always thrilled when I get to write a component like this. So this is a button and it includes a className.

We're back in React land. So we're gonna use that big-link class again. onClick, and inside of our onClick I'm going to addItemToCart and pass in the item, and then Add To Cart. And that's the whole thing, very, very simple React component, probably not worth bringing in the entire React library.

But again, this is for demonstration purposes. So back in our shop-items, where we have that TODO for the cart, we want to replace this with our React component. So up at the top here we can import, AddToCart from components and add-to-cart. And then down here we are going to replace this chunk of code, this TODO item with our AddToCart component.

We're gonna pass in the item from Astro. So the same item that we have here can be passed into the React component as a prop. So no magic or anything necessary for that. And then we need to set it to be client:only. And I'm not gonna use anything other than the client:only.

So let me talk about these for a quick second. So, by default, you don't get any client interaction. Astro lets you selectively hydrate using any of these attributes here. We are using the "only" option because this button won't work if you don't have JavaScript enabled, right? So we're making this into a single page app, it's just a single page island.

It's one little island of interactivity that only works if JavaScript is enabled. If we had something that works and is progressively enhanced as a component, then we can use client:load or client:visible. I really like client:visible because what that means is that the component won't rehydrate until it's scrolled into view.

So if you're working on a dashboard and that dashboard is several page heights long, and you've got some stuff that's really interactive at the bottom, somebody might not ever scroll down to that. So, why load that JavaScript and use up their network bandwidth? Instead, you just use client:visible and under the hood Astro is using, I believe, an intersection observer.

And when the component gets close to the viewport, it'll hydrate that component for you. And the user's none the wiser, but they just spent a few less kilobytes and they're probably happier for that. Idle means wait for the first moment that the browser is idle. Load is treat this like regular JavaScript and it can be part of the blocking load.

Media, I think you get to set on the same thing as a CSS media query. I haven't actually used that one and I haven't had a reason to use that one, so I'm not gonna pretend I know how that one works. [LAUGH] But so we're gonna set this to be client:only.

And again, because we're using multiple frameworks, we're gonna use React, set that =react and Save. Okay, so assuming I haven't typoed anything, this is going to work now. So I can come in here, we can shop for some sandwiches, and start adding things to our cart, and we get those items if we want to.

And remember, I'm clicking on a button that's powered by React. And this cart is powered by Solid. And it's all linked together using Nano Stores. So as I'm updating these, they are working as expected as if they were all using the same framework. Because Astro is acting as an umbrella and Nano Stores gives us the ability to quickly relay data between these different islands of interactivity.

So this is pretty powerful stuff, right? I was blown away when I saw this first work. And I think it's really just such a powerful testimony for, you can take this a lot further than you may have expected. And getting those benefits of the fact that if I go in here and disable JavaScript, you disable JavaScript and I reload the page.

What we get here is a note that you need to order by phone, but you can still see all of these things. The shopping still works, the ability to order is still there, just by phone. And we didn't lose the core functionality of the website. And then when I re-enable JavaScript, We get this additional functionality, but we didn't have to rehydrate this.

I didn't have to load and execute component code to get these images and text that aren't dynamic back on the page. Only this Cart, and only these Add To Cart buttons have to be loaded and executed. So this is a great way to build some very dynamic experiences in such a way that you're not adding unnecessary code to your page.

You're only bringing in what's necessary to get the job done that you need to get done. There's not any just in case code. There's not any you gotta use it because you got to go all in to get the features of this thing. It's just selectively as you need it, add one or more features at a time to get that going.

>> I just wanted to know if it's possible to use Nano Stores to maintain state across pages?
>> Yes, there are extra things you can do. You can put it into IndexedDB, or local storage, or something like that. And then kinda rehydrate it out. There are extra packages that make that work, okay.


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