Back

State Management in React With Valtio

State Management in React With Valtio

State management for React is an important issue, and it can be challenging to decide which of the libraries to use since there are the correct times and places to apply each. Valtio offers a simple, performant, and flexible solution that is well-suited to many projects, and this article will tell you all about it.

One tool used for state management is Valtio, which uses proxies to provide a mutation-style API. Proxy classes serve as an interface to another object. In its broadest sense, a proxy “wraps” the object, and to access the object, one has to pass through the proxy so, the proxy can do additional operations before returning the object. We can proxy almost anything. In the following sections, we’ll show how to use Valtio with React, and you’ll see it’s an easy way of working.

Why Choose Valtio as a state manager in React

Valtio is a lightweight and intuitive state management library for React that offers several benefits over other state managers, including:

  • Minimalistic API: Valtio has a simple and easy-to-learn API, making it less cumbersome than other state managers.
  • Reactive updates: Valtio uses Proxies to create reactive updates, meaning that state changes are reflected automatically in the UI.
  • Performance: Valtio has a small footprint and is highly performant, making it an ideal choice for projects that require high performance.
  • Server-side rendering support: Valtio has built-in support for server-side rendering, which means that your app will smoothly work whether running on the client or the server.
  • Flexible data structures: Valtio supports flexible data structures, such as maps and sets, making it easier to work with complex data.
  • Easy integration: Valtio can easily integrate with other libraries and tools, like React and TypeScript.

Getting Started

We will start by creating a new React application.

npx create-react-app simple-state-with-valtio

Next, we install Valtio.

yarn add valtio

Then we import the proxy and useProxy functions from Valtio into our app.

import { proxy, useProxy } from "valtio";

Our React component uses the useProxy function to create a local snapshot that tracks changes while the proxy function creates a new proxy state.

Components State

Components are a user interface’s building blocks that encapsulate a UI logic and can be reused throughout an application. A component can represent a small UI element like a button or a more complex UI element like a form or a modal. They are JavaScript functions or classes that return a React element, which describes what should be rendered on the screen (React element is a lightweight description of what to render, consisting of a type, props, and children)

Valtio has to be a part of the React lifecycle to segregate component states for reuse. You can wrap a proxy in a ref, passing it with props or context. We will discuss how to do this in the outline that follows.

Here is a demonstration of how Valtio lives in the component state:

import { proxy, useSnapshot } from "valtio";

/** use context to pass password state */
const PasswordButtonContext = React.createContext(undefined);
const PasswordGeneratorStateProvider = ({
  children,
  numbers,
  length,
  symbols,
}) => {
  const state = React.useRef(
    proxy(new PasswordState({ numbers, length, symbols }))
  ).current;
  return (
    <PasswordButtonContext.Provider value={state}>
      {children}
    </PasswordButtonContext.Provider>
  );
};
// wrap in a custom hook for ease of use
function usePasswordGeneratorState() {
  const passwordState = React.useContext(PasswordButtonContext);
  const snapshot = useSnapshot<PasswordState>(passwordState);
  return { passwordState, snapshot };
}

export default App;

OUTPUT

-

We created a PasswordButtonContext using the React.createContext function. This context then provides the state of the password generator using the PasswordGeneratorStateProvider component. Finally, the usePasswordGeneratorState hook lets us access the password generator state and its snapshot. Here is the link to the complete code on GitHub.

Note useRef is a React hook that allows us to create a mutable variable that persists between renders of a component. It returns an object with a single property, current, that holds the current value of the reference. It is used when we need to modify a value without causing a re-render of the component.

useContext is a React hook that allows you to access data and functions from a parent component’s context object. It is often used to simplify data management and make data sharing between components more efficient.

A full explanation of the features of Valtio to use in manipulation states is discussed below.

Session Replay for Developers

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — an open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

Proxy and useProxy

In the components state, the proxy tracks change to the original object and all nested objects, notifying listeners when an object is modified.

import { proxy } from 'valtio'
    
const state = proxy({ count: 0, text: 'hello' })

The useProxy is a hook provided by the Valtio library that allows you to create a reactive binding to a Valtio proxy object in your React components, making it easy to read and update the state in a performant and scalable way.

When useProxy is used with a Valtio proxy object, it returns a reactive state object that automatically updates when the original proxy object changes. This functionality shows you can use the returned state object to read the current state of the proxy object, and any changes you make to the state object will automatically reflect in the UI. Here’s an example of how you can use useProxy with a Valtio proxy object:

import { proxy, useProxy } from "valtio";

const state = proxy({
  count: 0,
  text: "",
});

function Counter() {
  const proxyState = useProxy(state);
  return (
    <div>
      <p>Count: {proxyState.count}</p>
      <button onClick={() => ++state.count}>Increment</button>
    </div>
  );
}

export default function App() {
  return (
    <>
      <Counter />
    </>
  );
}

-

In this example, we define a Valtio proxy object called state with a count and a text property. We then use the useProxy hook to create a reactive binding to the state object, which we store in the proxyState variable. Finally, we use the proxyState object to display the current count value in the UI and to update the count value when the button is clicked.

Using useProxy, we can create a reactive binding to the state object that ensures that our UI is always up-to-date with the latest state values and that changes to the state are always reflected in the UI.

Snapshot and useSnapshot

One of the critical features of Valtio is the snapshot and useSnapshot functions.

The snapshot function creates a read-only copy of your state in the component. It is useful when you want to pass the current state of your application to a component or a function without allowing it to modify the state directly. The snapshot function returns a plain JavaScript object that represents the current state of your application.

Here is an example of using snapshot in Valtio:

import { proxy, snapshot } from "valtio";

const state = proxy({
  count: 0,
});

console.log(snapshot(state)); // { count: 0 }

The useSnapshot function creates a React hook that allows you to access the current state of your application in a component. It is similar to the useContext hook but only updates the component when the state depends on changes.

Here is an example of using useSnapshot in Valtio

import React from "react";
import { proxy, useSnapshot } from "valtio";

const state = proxy({
  count: 0,
});

function Counter() {
  const snap = useSnapshot(state);
  return (
    <div>
      {snap.count}
      <button onClick={() => ++state.count}>+1</button>
    </div>
  );
}

export default function App() {
  return (
    <>
      <Counter />
    </>
  );
}

-

In this example, the useSnapshot hook returns a read-only snapshot of the state, which is used to render the count component. The state object is updated when the increment button clicks, triggering a counter component re-render.

Conclusion

A typical modern app requires state info management, making Valtio a powerful tool since it is straightforward and robust. Moreover, it combines the potential of proxies in React.js and JavaScript to simplify and modify state data. Here is a GitHub repository for managing states in Valtio. You can also check the Valtio documentary for other related API lean to the library.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs and track user frustrations. Get complete visibility into your frontend with OpenReplay, the most advanced open-source session replay tool for developers.

OpenReplay