 Hey everybody Thank you for coming to my presentation. My name is Jack Taranto. I'm a front-end developer. I work at previousnext. I've been working with Drupal for probably about 15ish years and I've been doing react stuff in Drupal for probably about four years or thereabouts. So, yeah, in this session, I'm going to be building, walking you through, building a very basic decoupled app using Drupal and some technology called react query. So first up, I'll just give everyone a really brief walkthrough of the tech stack. So Drupal, I'm guessing everyone's heard of Drupal at this point. So we're going to be using a fresh vanilla Drupal 9 installation. I've done very little with it. I've enabled the JSON API module and I've set up a really basic content type which I'll walk you through in a minute. Next up is react. Yeah, I'm guessing probably everyone's heard of this too. It's made by the Evil Facebook Corporation. I think I can say that because I've changed their name now, but yeah, I'm I've bootshot it with the react starter kit. So that's also maintained by Facebook. It just gives you a basic react app setup. And we're going to be building react components and using something called react context. And react query is a technology you might not have heard of. It's something that's created by a really smart guy called Hannah Lindley and sort of a framework for fetching and caching API data in react. So I'll be walking through that. And I'm going to do it all through a live coding exercise. So I've been sacrificing a really large number of goats to the demo gods. So hopefully this works out all right. So yeah, first up, let's take a look at the Drupal site. So yeah, as I mentioned, it's just a vanilla Drupal 9 install. I've enabled the Claro admin theme and yeah, I've set up this movie content type. And you know, these are my top five studio Ghibli movies. So if we just jump into one, we'll see the fields I've set up. So yeah, we've just got the title field. I've got this media field, which is probably the trickiest part of the API stuff. So we'll be walking through getting media out of JSON API. I've got this WYSIWYG field. So there'll be a point of making sure we grab the processed text from that field. And then yeah, we just got a couple of string fields there as well. And if we look at the front end, this is the Olivero theme. No, it's looking pretty good, isn't it? We might not worry about building a decoupled application at all. That looks pretty good to me. Let's just leave it at that. Maybe not. Maybe we'll keep going. So here's our JSON API response. And this is the URL I'm grabbing there. So yeah, it's got the include, which pulls in the media entity. As I mentioned, probably the trickiest part there. So yeah, JSON response has got everything in it. I haven't bothered filtering anything out. In production, you can filter out all this field data that you're probably not going to be using. But I've just got it all in here to show you guys how that works. Here's our synopsis field. It's got the processed HTML. So this is safe to use. We can just pull that in to react and render that directly. We don't have to worry about there being anything malicious in your script tags or anything like that. And then we've also got our media field data in here as well. So we're going to end up having to kind of drill into this to pull out our file URL so we can render that poster. Yeah, so that's the Drupal side. And yeah, this being decoupled, we've actually got a separate application. So we're just using Drupal for the content. And our React app, which is empty at the moment, is going to be contacting Drupal, pulling this API response, and then rendering a bunch of movies inside it. So yeah, let's jump into the code. I've just set up a basic project. I've got two folders here. The API folder has got a... This is where the Drupal 9 installation lives. And then I've got this app folder here, which is where our decoupled application lives. And this all comes from Create React app. I've got like a bare bones project set up here with some components. I've got some CSS here that I've written already. I'm really proud of this CSS. It's probably some of the best CSS I've ever written. So let me just check that out. But yeah, we may as well get started now. So the first thing we'll do, we'll start at kind of like the bottom level, so with the actual movie itself. So yeah, we'll just call this component movie. Needs to take some props. And the props are just going to be the fields that we've got in Drupal. And we can call them whatever we want, but we'll just take the basic name. That poster prop is going to be the URL to the image. So we'll enter all this thing up. Yeah, it's a good time. It's a good process to validate these using prop types. So I'll do that here. And they're all string fields, but prop types are powerful for validating all sorts of data. Okay, so it's looking good at that point. I'll start writing some HTML now. And yeah, as I said, I've got all the CSS written already. Just going to use an image tag. And next to our class. And yeah, the source is just going to be that image prop there. Cool. And I'll hack in some out text using the title. So I'll just paste in some HTML prepared earlier for the rest of it. Let me see any tag there. So yeah, what have we got here? We're just, I'm just printing out all the props. So we've got our title here. This dangerously set in our HTML. This is a react prop you can set on a div tag. And basically reacts wave saying, do you know you're going to be rendering out some HTML? It's not dangerous in this case, because we're going to be using that processed text value. So Drupal is handling all the processing and making sure that there's nothing dodgy in there. So yeah, we just pass that through using that method. And then yeah, we just got the rest of the fields there. So let me just remember to import the CSS as well. Okay, so yeah, that's our movie component written. So yeah, next up, we're going to jump into the guts of react query. So there's a bit of boilerplate stuff to get react query up and running. There's some components there that we need to implement first. And I'll kind of wrap them inside this component called a JSON API provider. So it's just implementing a react query, but the implementation can be specific to JSON API. We can have caching settings in here and things like that, but we might want to be unique. So yeah, just call that JSON API provider. To use react query, I need to create this thing called a query client. It's pretty simple to implement. Yeah, this all this just comes straight from react query. Once I've created a new version of that, I can implement this component, which also comes from react query, the query client provider. That just gets passed the client prop with query client as its value. And the whole application ends up getting wrapped in this provider. So we just need a children prop. And then we'll just pass that through there. I won't bother with prop types in this case. So yeah, that's basically all you need to get react query up and running. So yeah, as I said, I'll wrap our application in it. So let's do that here inside of this render function. Yeah, so now anything down the tree can use react query. So I'm going to roll in my next component. Now it's this movie provider component. It's going to be fairly similar, but this is where kind of the meat of the fetching and stuff goes down. So yeah, I'll just call it movie provider. I won't worry about prop types for this one either. So yeah, first up is to create the context. So in react context is kind of like a store of a particular value. That value can be whatever you want it to be. So in this case, it's going to be the list of movies that react query returns. And that means like any component inside your application can grab these movies and just pull them out with very little code. So yeah, I'll just call it a movie context. Just use react create context function. You need to pass it a default value. It's best just to use null in this case because we want to be able to check, you know, if react query is fetched anything. And if it hasn't fetched anything, it's just going to be null. That's good for like initial rendering of your application. So next up where I'll create this custom hook, which our components can use to get the movies. I'll just call it use movies. And this is just a good little trick. It's basically like just a wrapper around react use context hook. And you just need to pass it the context that you want to be using. So yeah, now we've got that set up. I can create my movie context provider component. Just do it like that. It takes a value. It takes a value. Like I said, that value can be anything you want. I'll fill that out in a minute. And yeah, we're going to be wrapping everything again. So just do that children thing. Yeah, cool. So now we actually get to do the fun part and implement the use query hook. So do that in the top of the component. So react query returns a whole object with a whole bunch of things. You've got like values in there for is loading is fetching and the actual data of the, you know, your query function comes back in something called just in the key called data. So I just use object destructuring to pull that out. And yeah, use query. It's a hook. So you need to give your query a name, query key that can be just any string. And then you need to pass it a function. So react query doesn't actually handle any of the fetching or anything like that. It sort of manages the state itself and how often it fetches and how it caches data, all that kind of important stuff that you really don't want to have to worry about. But it doesn't provide any kind of default way to actually fetch the data. So yeah, we do that by just writing our own function that does it. So it's quite nice in that regard that you can have like a total custom layer. It's handy working with Drupal because you might have different APIs to access. So, yeah, I'm just going to use default vanilla JavaScript fetch to do that. And I'll write that using the async function syntax, which is pretty neat. Yeah, so I want a response. We want to fetch it. We need a URL. I'll just jump back to my tab and we're going to hit the same URL here. Paste that in. Yeah, so that's almost all you need. There's no kind of default error handling that works with fetch and react query. So we just need to write that ourselves. Basically, you just want to throw an error if, you know, for whatever reason, the response is not okay. That way, that'll trigger, you know, the inbuilt error handling that react query has. Yeah, so paste that in. And then, yeah, I'm just going to grab the keys from our JSON response. And I'll do that using this neat object destructuring syntax. We want to await that. I missed the await there, too. Yeah, we want to await this JSON response. Now, yeah, and then we can return that data to our use query hook. However, that data is pretty gnarly. Like if we go back and look at it, there's like a whole bunch of stuff here. We could just return, you know, whatever we wanted. But we could just return everything that's here. But it would be better to narrow it down for our application and make it a bit... So, another function which handles that, and it's going to be a process called normalizing. Really, just normalizing that crazy JSON API data. And, yeah, this is going to be just a custom function to handle this, basically. It's good to split all this stuff out. It makes it easier just to unit test each individual function at that point. So, yeah, this is just going to create a movies array. And I'm going to loop over that data key that we're getting back from fetch. Cool. So, this is where things get a little bit tricky. We've got... we really need to get our file URL from here. Let's kind of decide this array, that we're going to have this ID here, basically. And, you know, we have to get that ID out of the data array. So, I've just got some stuff prepared earlier, but there's probably a whole bunch of needed ways to do this stuff for now. I'm basically just filtering out our relationships array to get the ID for the media entity. And then, it's a bit tedious, but you've got to do that again to get the file entity so that we can get the path. So, we can get the URL, sorry. So, that's just filtering based on these IDs. It's something you'll get used to when you're working with JSON APIs, the Web stores data in some responses. So, yeah. Then, now that we've got that, we can push a new item into this movies array, and it's going to contain the structure. So, if we jump back to our movie component, it wants all of these props here. So, we can structure our data in a way that will match this perfectly. And that'll make it a lot easier to push stuff around. So, yeah. That's the code there. So, it's just looking through all the different pieces of the JSON API response and putting them in a really nice neat little object that we're going to use later. I've just hard coded the site URL in there. You could probably do that in a few better ways, but it would do the job here. Also, making sure I'm getting that process key out of the WYSIWYG field. I'm not going to pass through any bad data. So, yeah. Now that's here. I shall return it. Okay. And, yeah. I just need to call this function now. Pass it through both of those pieces. So, yeah. Basically, now I just need to add this function to my use query hook. So, bunch of movies. And I'll add the data there to the value. So, whenever we call use movies, it's going to call, you know, it's going to get this data value. And that data should be a nice neat array of movies, basically. So, that's finished. I've just got to wrap the application in the movie provider. So, the whole thing can get access to those movies. So, yeah. Now we just need a component to render them. This is the movie list component. Yeah. So, another, it's fairly simple as well in this case. It's called movie list. It's not going to have any props because it's going to get its data from that hook. So, in the top of the component, we'll just ask for the movies and we use use movies. So, yeah. Now we should have access to them. We'll just put some conditional logic at the top here. We only want to render the list, you know, if there's anything there. So, it'll be null or empty or whatever if it hasn't come back. Yeah. We've got the class already written for that. And, yeah, just do a map to loop over each movie. Okay. So, yeah, we'll call in our movie component now. So, first things first, got like all of these props. We don't actually need to go and fill them all out because we know that our data structure is going to match what the component is expecting. We can just use property structuring and just go like that to bring in the whole movie. We're using maps. So, we do need a key and we've got the UUID for the movie as the ID. There. So, that's, yeah, that's really, I think. Yeah. Yeah. That's going to grab the movies and render them out one by one. So, yeah, I just need to add that to my app. Yeah. Movie list. Doesn't take any props. Yes. I think that should be it. Just kind of quickly review everything. We've got our basel movie component with its markup. It's including CSS. We've got our boilerplate for react query. We've got our movie provider, which is doing all the chunky stuff. Hopefully this works. If we have a problem, that's probably something in here that I've missed. And, yeah, we've got our application wrapped up in its providers. So, yeah, let's jump into the browser and see if that's working. Oops. Refresh. Oh, it's not working. What's going on here? Oh, dear. Oh, dear. We've got a whole bunch of network requests failing. Cause. Cause cross origin. This sort of thing comes up all the time, doesn't it? JSON API doesn't have any cause headers. So, we need to add cause headers to JSON API before we can actually request any data from it. There's a bunch of different ways to do it in Drupal. You can add some code to, like the services.yaml file, but a really neat way to do it in this case is just to use an event subscriber. So, I've just got a custom module here. I can drop this in. And I've already pre-written it because it's a bit gnarly, but paste that in. So, yeah, this is a Drupal event subscriber. It's looking for the JSON API path. So, whenever it sees that path, it's going to add these two headers to the response for us. And these are the two headers you need for cause. Allow access control origin from anything, and you also need this very origin header as well. So, that's important to make sure you can access the API from multiple domain names. So, yeah, now that that's in, I just need to also add the YAML entry for it. So, Drupal knows where to look. And I also need to clear my case. Case clearing, case clearing, case clearing. Case clearing, case clearing, case cleared, cleared, success. Cool. Now, we'll just refresh our requests. And yay, we've got our headers here now. These are the two headers we've added. If we go back to React, look at that. React query will automatically refetch data when you focus the window. So, it's refreshed. It's got those new headers. And yeah, it's brought in our movies for us. So, there's a lot of neat features in React query. I'll just take you through a handful of them now. The DevTools are quite great. Yeah, I'll just add them in. You add them into your query client. So, yeah, you can have these in here the whole time and they won't get built if you're in production development mode. They won't get added. So, you can just leave them in your application like that. That gives you this little icon in the bottom corner which you can bring up. And yeah, now you can see the actual query. So, yeah, we've got our movies query. You can see if it's stale or not, it's kind of a process that React query uses to determine if it should refetch new data. So, you can set any amount of time for data to be stale. And then, once it's stale, it will go back and refresh. Refresh it. It'll hit the API again and put in new data. And it does all of that without triggering any new renders as well inside your app. So, it's super quick. We can see our data that's been returned here as well. Yeah, you can see the settings and stuff, how long things are cached for and all kind of stuff. So, yeah, that whole kind of live refresh thing that it does is a bit of a game changer for various different applications. So, we can see like we've got four movies in the list here. We're missing Howl's Moving Castle. So, it's unpublished at the moment. If I publish it and then jump back to the application, it's done another background refresh and it's added that entry for us. So, yeah, there's all sorts of use cases around that if you need to have up-to-date data being displayed. And, yeah, it's kind of a line, I guess, on your back end, on your APIs being really well cached and, you know, having proper cached tags and all that kind of stuff as well. But it is a super handy feature. Yeah, so I've been speaking for half an hour. So, I think that's everything I had for my demo and live coding exercise. So, I'll, yeah, put it out there for some questions. Hi, thanks, Jack, for the live coding. Definitely, your sacrifice worked. You can see all everything working. There are a few questions coming in, but I'll start with one of the ones. Where would personalization, so if I were to personalize this site, right, and, you know, based on user who's visiting this site, the React part, where would the personalization will be performed, which layer, whether it be Drupal or React? And, you know, so how would you handle that part? Yeah, personalization is an interesting one. I guess it requires, like, having some information about the user, which needs to be stored somewhere. So, yeah, you've got that info that would, you know, that would have to live on the Drupal side of it. The front end knows who the user is, presumably, so you can just put a request back to Drupal to get that info. And then the actual, like, logic of what the personalization is, should display to that user would all then, you know, ideally happen in the front end. So, you'd have, you know, all that logic written in your front end framework, and it's really just using the data that it gets back from Drupal to display that. And that might involve, like, making more requests back to Drupal to get different data or something like that. But, yeah, I think the front end is super capable, and everyone's got a super fast device in their pocket, which can, you know, do all that kind of logic. Really quickly, you definitely don't want to be performing that logic on your servers, you know. Sounds good. Thanks for that. The other one we just got, it is just adding, like, course headers, which you did in the, just to, you know, cross-reference query. Does that pose any security risks? Security risks from querying the APIs or? Yes, yeah. Like, you just allow it to start, or maybe you would be doing it in production in a different way. But, yeah. Yeah, I mean, in this case, these are, yeah, these are like, yeah, I mean, you can push with JSON API, but, like, ideally, you're just doing get requests. So, yeah, I mean, I guess that comes down to the security of your application, but it's always good to have these APIs open so that you can just pull the data out of them without too much fussing around, I think. Yeah. On the same note, I've just read in the discussion forum, Stuart posted that, ultimately, you can proxy the API from the front end, which could be another way. Yeah, okay. The last one we have here, and plus, if anything more comes up, is, you've been working with JSON API. What are the limitations of the JSON API, or through this case, like as a content store, who's giving you the content? So, what are the limitations of JSON API, which we should be aware of when doing JSON API? Yeah, JSON API has got lots of limitations. Yeah, it's, I mean, as you can see, just the process of pulling our data, you know, included data, especially when you're working with paragraphs, it's, you know, can be a bit of a nightmare, but like besides all that, there's a hard limit on how many items you can get back. You can only get 50 items back in one go. So, you kind of need to be aware of that if you're trying to query it for large amounts of data in one go. And, yeah, Lee mentioned in his keynote this morning, the revision stuff. So, that's always been a major limitation, pulling out older revisions and, you know, anything that's not published, basically, is really difficult to get at. So, yeah, that's going to be going away soon. I think that'll make it a lot more powerful. Yeah. Cool. Thank you for that. I'm just very fond of anybody else that's in the other questions. There's one question from, from Stuart, which I'm, I just was, yeah, yeah. So it's, so it's the live of taking polling the API, a live of taking polling the API or using web sockets. If not sockets, have you looked at the couple of groups with sockets? Yeah, I haven't actually. So it's, I mean, it's just polling the API. It's doing whatever, whatever you tell it to do inside that query function. It literally just runs that function and then gets the data back. It compares the data and then it kind of decides whether it should update or, you know, just not do anything and update your app at all if the data hasn't changed. So, yeah, I guess you can do anything that you want in that function, but in this case, it's just, it's just polling the API. So, yeah, ideally that is heavily cached, which it almost always is. So, yeah, but you haven't, I haven't done anything with web sockets. Thank you for that. Any other questions? Yeah, react overview. Yeah, so, I mean, that's, I think that's the beauty of the decoupled approach. It doesn't really matter what framework you use. Yeah, you can really just depends on your organization and the capabilities that you have available to you, what your developers prefer working in. So, like at the start, like I've been working with React for quite a few years now. I haven't really done much stuff to do at all. So, just kind of focus my work on React and, you know, that's why I'm able to use it at this point. So, I guess it takes, you know, that's really question, personal question for your organization and what framework you want to use. They're all equally as powerful. So, yeah. In your experience when with this decoupling things, have you ever seen a site kind of using a widget from React and a widget from you? Or is that possible at all? Like, you know, having a part of site rendering from you and a part of site. Like just to, you know, just to kind of understand the power of decoupling. Yeah, I guess it depends on what you're doing. We're doing a lot of partial decoupling. So, we're running like a Drupal site with a Drupal theme. And then we've got a series of apps inside the theme. And they're, you know, they're predominantly using React. But you've got to, I guess, you know, in that approach Drupal is still rendering the page. But you can drop any kind of application in that you want. So, you could definitely use multiple frameworks side by side. I guess the main thing is there, you probably wouldn't want to. You're going to have heavy, you know, each, each framework's got its own heavy library that comes with it. But, yeah. Yeah. Have we got, have we got any more questions there? We can probably wrap up, if not. I don't see more questions. Yeah. I think that was a very lovely presentation and, you know, life-quoting. Thanks for sharing that with us. Thanks, everyone. Thanks so much for coming along. Yeah.