Migrate to Netlify Today

Netlify announces the next evolution of Gatsby Cloud. Learn more

ContactSign Up

How to Use Function Props with Gatsby’s Slice API

Paul Scanlon
November 14th, 2022

In case you missed it, Gatsby 5 shipped with the new Slice API!

Gatsby’s new Slice API can be used to help speed up common updates across your site. By pulling out common components into separate HTML files, common components can be built separately and “stitched” together with existing pages. 

You can read more in the docs here: Gatsby Slice API or, in this excellent blog post by Gatsby’s Product Manager Josh Johnson: The Gatsby Slice API: High Precision Incremental Builds

As good as the Slice API is, it does come with one or two restrictions. To be clear, these are by design rather than an oversight. One such restriction I ran into was when I attempted to pass a prop of type function to the Slice component. 

E.g

Using a Slice in this way will result in an error similar to the below.

Slice “header” was passed props that are not serializable (not serializable “function” type…)

In this blog post I’ll explain why this happens, and one method I used to work round this restriction, but first, a simple demo.

A Simple Theme Toggle Demo

I recently ran into the “function prop” issue myself when attempting to pass a function that controlled a dark/light mode Theme Toggle.

I’ve prepared a minimal example site and repository to better demonstrate the functionality I needed. 

The demo site has a Theme Toggle in the Header component. Header components are a prime use case for the Slice API because they’re often used / reused across every page of a site. 

The Problem With Function Props

From the very start of the Slice API project the team were focussed on builds with incredible precision, in fact, I have it on good authority that the Epic was actually called “High Precision Incremental Builds”. 

In order to achieve the highest precision possible, any props passed to the Slice component need to be serializable. Once serialized they can be stored and used on subsequent builds, or “slotted” into cached HTML pages. 

Serializing functions for diff comparison can’t really be achieved in a reliable way because Javascript functions are non primitive types and can’t be serialized in a way that Gatsby could use to perform a diff, or high precision build.

Function Serialization 

Here’s a simple data object which I’ll use to demonstrate the issue. It contains a title and a date, both are typeof string.

If i use JSON.stringify(data, null, 2) to serialize this object i’d see the following output.

Serialization of primitive data such as Strings is ok because the output can be compared in a reliable and predictable way. 

Sadly this is not the case with functions. 

Here’s a simple function for demonstration purposes.

Using the same approach as before, JSON.stringify(sum, null, 2) to serialize this function I’d see the following output

I could, as an extra step, cast the function as a string before serializing it like this, JSON.stringify((""+ sum), null, 2), which would output the following.

Or, another option would be to do something like sum.toString(), which would output the following.

However, using this method will only work on user defined functions, not native functions like this, Math.abs.toString(), which would output the following.

Hopefully you can now see why function serialization isn’t the rock that high precision builds could be built upon

A Better Developer Experience

The team believes it’ll be a better Developer Experience to not support function props at all, than to support them in an unreliable and error prone way. But all is not lost!

Enter Gatsby Staff Software Engineer / Mega Legend Grayon Hicks with one solution.

React Context

Rather than attempting to pass a function through a Slice, you can “provide” the function via React’s Context API and “consume” it from within the Slice. — Sneaky ay!

Here’s some code snippets from the PR branches in the example repository.

  • The darkMode prop is of type boolean and will either be true or false.
  • The handleTheme prop is of type function.

 

main (without Slice API)

The below snippet is from the main branch and show’s how you’d typically pass props “through” a Header component.

example/error-branch

This snippet is from the example/error-branch branch and shows an almost direct translation if the Header component were a Slice. This won’t work!

feat/add-context

What will work however is, if you move the props “inside” the Header Component so the props can be consumed via React’s Context API, leaving the Slice Component with only the alias prop.

And here’s what the “inside” of the Header Component looks like, both the darkMode and handleTheme props are made available via React’s Context API Consumer.

Using React Context With Gatsby

Now… this is all well and good, and you can see this working on this Gatsby Cloud PR Preview but, are you now wondering, how to use React’s Context API with Gatsby? 

I got ya back, Jack. I’ve written a post on my blog and aptly named it: How to use React’s Context API with Gatsby — (didn’t see that plot twist coming, did ya!) 

I’m sure there’s a few other ways to work round passing functions into Slice Components, most, I imagine will require a little bit of a refactor, but the Slice API can really help speed up builds when site-wide code or content changes occur in common components, and I for one totally think it’s worth the effort.

Lemme know if you have any q’s, as always, I’m on Twitter: @PaulieScanlon

Ttfn

Share on TwitterShare on LinkedInShare on FacebookShare via Email

After all is said and done, structure + order = fun! Senior Software Engineer (Developer Relations) for Gatsby

Follow Paul Scanlon on Twitter

Tagged with Gatsby 5, Slice APIView all Tags

Talk to our team of Gatsby Experts to supercharge your website performance.

Contact Gatsby Now
© 2024 Gatsby, Inc.