Introduction
Welcome to our latest blog post on SolidJS, where we delve into the world of the Context API. Context API is a popular and versatile feature in SolidJS, allowing developers to pass data and functions through the component tree without the need for props drilling.
In this post, we will discuss how SolidJS implements the Context API, including the creation of contexts, sharing Signals and stores, and utilizing them within the components. Whether you are a seasoned developer, or just starting out, this post will provide valuable insights into the use of Context API in SolidJS and what are the advantages in the Reactivity ecosystem. So sit back, grab a cup of coffee, and let's dive in!
What is SolidJS?
SolidJS is a unique and powerful JavaScript framework that is quickly gaining popularity among developers. One of the key features that sets SolidJS apart from other frameworks is its reactive nature.
How about reactivity?
Reactivity is a programming paradigm through which the application automatically updates and re-renders when the data changes. This means that developers do not have to manually update the view when the data changes, saving a lot of time and effort.
SolidJS achieves this reactivity by using a virtual DOM which is a lightweight representation of the actual DOM. This virtual DOM is then used to update the actual DOM, making the process of updating the view much faster and more efficient.
Performance
Another advantage of SolidJS is its performance. SolidJS is designed to be fast and efficient thanks to its use of a virtual DOM and a functional programming approach. By using functional components and immutability, SolidJS is able to optimize the process of re-rendering, resulting in a smoother and more responsive user experience.
In addition to its reactivity and performance, SolidJS also has a small footprint and a simple API. The framework is lightweight and easy to learn, making it a great choice for developers of all skill levels.
Signals:
SolidJS Signals are a powerful feature that allow for easy communication between different parts of your application. They are similar to events or hooks in other frameworks, but with a few key differences. One of the key advantages of Signals in SolidJS is that they are fully reactive, meaning that they automatically update and re-render when the data changes. This makes it easy to create responsive and dynamic applications without having to manually update the view.
To use Signals in SolidJS, you need to first create a signal by using the createSignal function.
const [count, setCount] = createSignal(0);
Store
In SolidJS, a store works similar to other frontend frameworks. To keep things light, SolidJS creates underlying Signals only for properties that are accessed under tracking scopes. All Signals in Stores are created lazily as requested. The createStore call takes the initial value, and returns a read/write tuple similar to Signals. The first element is the store proxy which is readonly, and the second is a setter function.
What About context?
SolidJS provides a context API to pass data around without relying on passing props; this is useful in sharing Signals and Stores as described above. According to SolidJS docs: “Using Context has the benefit of being created as part of the reactive system and managed by it.”
Getting Started:
First, let’s create our context:
import { createContext } from 'solid-js';
const initialState = {
count: 0,
name: "John Doe",
isLoading: false
};
const MyContext = createContext(initialState);
Then we can consume our recently Context created:
export function MyProvider(props) {
const [count, setCount] = createSignal(props.count || 0),
counter = [
count,
{
increment() {
setCount(c => c + 1);
},
decrement() {
setCount(c => c - 1);
}
}
];
const [name, setName] = createSignal(props.name || '');
const [isLoading, setIsLoading] = createSignal(props.isLoading || false);
return (
<MyContext.Provider value={[counter, name, setName, isLoading, setIsLoading]}>
{props.children}
</MyContext.Provider>
);
}
export function useMyContext() { return useContext(MyContext); }
To use context, we'll first wrap our App component in order to provide it globally:
const App: Component = () => {
return (
<MyProvider>
<Counter />
<Loader />
</MyProvider>
);
};
export default App;
We can now consume the context and our components will look like this:
export default function Counter() {
const {counter: [count, { increment, decrement }], name, setName} = useMyContext();
return (
<>
<div>{count()} {name()}</div>
<button onClick={() => {setName('ThisDot')}}> Click Me </button>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</>
);
};
export default function Loader() {
const {isLoading, setIsLoading} = useMyContext();
return (
<>
<div>{String(isLoading())}</div>
<button onClick={() => {setIsLoading(!isLoading())}}> Click Me </button>
</>
);
};
Conclusion
In this article, we were able to use the contextAPI to share the props we want across the app, and benefit from the performance of Reactivity because of that. This will make our application more readable, but also brings some additional benefits to the app which are as follows:
- avoid passing props down through multiple levels of the component tree.
- reducing the number of re-renders that occur when props are passed down.
- by isolating state and props to a specific context, you can make your code more organized and easier to understand.
- components that use the Context API are more easily tested.
Would you like to learn more about Signals and Stores, or SolidJS in general? You can see in detail how this was maximized in one of This Dot Labs' open source project starter.dev GitHub Showcases.