Check out a free preview of the full Reactivity with SolidJS course

The "Context" Lesson is part of the full, Reactivity with SolidJS course featured in this preview video. Here's what you'd learn in this lesson:

Ryan explains the Context API and demonstrates how to create a global state. Immutable stores that interface with libraries like Redux, Apollo, or XState can also be created.


Transcript from the "Context" Lesson

>> The next thing that I wanna actually show is context. I keep on showing this demo where we pull the signals out and just go, look, it's global, that's fine. But when you have things to consider, like server side rendering, you might not want to have a truly global state.

Because it could be shared between requests. So for that it still makes sense to put data in your app tree. And for that what we do is we use something called context which allows us to define a provider. And what a provider does is it basically is a way of injecting state into our tree.

And then somewhere further down in the tree, we can basically use another primitive to pull that state out and be able to read it directly. So I kind of made a very simple counter provider here where I created a signal. And I'm keeping Solid's convention of returning an array where there's a count.

And then made a few named operations like an increment and decrement. This is a very common pattern in Solid, where instead of passing the setter straight through you might actually make a specific update functions, right? So this is a simple counter. And then our provider just renders its children in between.

And essentially somewhere further down, we have this nested component that wants to be able to use our provider. That's the idea here. So to get started with a provider, all we have to do is decide where we want to inject it in our code. So what I'm gonna do here is I've got the CounterProvider imported.

And I'm just going to, sorry, CounterProvider, and we're gonna wrap our whole app with it. It's very common to have like global providers, so this way now our context is available to the whole app. And then inside our specific nested component, what I did was the way context works is you create a context object.

And then you generally kinda wrap your own provider from that created context object. But there's a useContext that lets you take that context and use it in that specific scope. And I've just wrapped this in a used counter for convention and for cleanliness. And what this lets us do is even though this nested component it's much further down in the tree.

It's not up here, it's in this other component because it's apparent to it. We have the ability to basically get our count, get our increment and decrement functions from our counter. And then, We have the ability to use our count signal. And this can be a store, you can put whatever you want in there.

And then we have the ability to go onClick, let's increment. onClick, let's decrement. And if all went well, we have the state now being injected from above. So this is this very powerful thing. It's just important to kinda note that, in this case, it's not just calling the function here and passing the value.

You're actually creating the reactivity that you wanna pass through. So between stores and signals, which can be used in and outside the components, we now have ability to kind of inject kind of global state. It can be hierarchical, you can use it for parts of the app, you can use it for the whole app.

So let's you can manage state more independently of the component tree. And it's important to note here there, is a no performance downside of using this approach, if you think about it. Because this doesn't cause any children to ever rerender. Just because this signal up here at the top of the app changed, it doesn't mean we have to trigger rerendering the rest of the page.

We're just passing a signal through. So like before, where our components literally all updated independently with all the signals, it's the same thing here. You can put as much state as you want in the context. You can do updates multiple times a second, 60 FPS in your context.

You're not gonna have any problems here. It's a single mechanism and it's super performant. And you can start seeing with these kind of powers, we actually can basically do almost all state management within Solid without a third party library. But some people do wanna use a third party library.

Maybe Redux or something, or Zustand these days. And you can do that with Solid, because we have a little trick up our sleeves. Which is I made a very simple use Redux wrapper here. But what we do essentially is we can get a store. And if you're familiar with Redux, the store has a getState() function.

So I'm just passing a Redux store into this useRedux hook. And the whole key here is their stores have a subscribe function that whenever they update, they call this function with the new data, essentially. And this could be RxJS, this could be any third party immutable data store.

Solid has, for the stores, I called it state for some reason, but this is the store here, a reconcile modifier. And if you do a reconcile modifier, you can pass large immutable data states. And the reconcile function will do a data diff for you. So it will find the specific key data points that have changed fine grained.

And then the store which is already fine grained, already tied to the specific updates, will update. So if you have a whole list of users. You get some new data from a API call, fresh data, it will diff the data, realize that only the street name on that one street changed.

And then the store will notify the UI to update that one point in the DOM. So there is a diffing mechanism when we need to fallback to it when using stores. So we have this ability to to do kinda similar diffing. And actually test this and benchmarks regularly against VDOM libraries for these kind of cases.

This our diffing performance is very similar to a virtual DOM library called Inferno. Just kind of get an idea of the kind of cost or overhead of using reconcile. In a lot of cases this kind of logic is gonna be hidden in your integration with a third party, like XState.

We've been working with XState to get an XState Solid integration. Reconcile and the stores are kind of underneath the hood. And then you just use XState as you normally would use XState, except whenever the state changes, fine-grained updates. Okay, that's basically it for stores, and global statement in Solid.

It'll work with the tools you already use, plus the inbuilt stuff is already quite capable on its own.

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