State management is an important concept in modern app development, especially for single-page applications. It is used to control and monitor actions, user inputs, and server responses. Popular libraries like Redux and MobX are often used by developers to manage state in React applications. However, these libraries primarily provide a way to access data globally without the need to pass props between components and pages. Unfortunately, they do not offer functionality for undoing or redoing actions in an application, or navigating to specific points in a series of actions. This is where the Crystalize.js library comes in. In this article, we will explore the Crystalize.js library and learn how to use it with React by building a photo editing web app with undo, redo, and download features. We will also compare it to Redux to understand its similarities and differences. You can find the source code for our demo project on GitHub. By the end of this tutorial, we will have an app that functions as shown in the video below: What is Crystalize.js? Crystalize.js is a library specifically designed for dynamic state management. It captures actions and data as “shards” and stores them in a state called a “crystal”. But what does this all mean? Interestingly, due to the way Crystalize.js handles data, it enables us to do things that are not possible with other reducers and state management solutions. For example, we can implement undo and redo functionality in an application. Because of this unique approach to state management, Crystalize.js introduces new terms such as crystalizer, crystal, shards, and base. It also provides a set of APIs including take, leave, with, focus, and more. Instead of explaining these terms upfront, we will discuss them in detail while working on our demo project in the following sections. This will give us a more practical understanding of the library and how it works. Setting up a React application with Crystalize.js To dive into Crystalize.js, we will set up a React app using the Next.js CLI. Let’s start by creating a new folder for our project. You can choose any name for the folder. For this tutorial, I will name it “dynamically-manage-state-with-crystalize-js”. Next, open the folder in a code editor like VS Code. In your terminal, run the following command: npx create-next-app@latest Follow the prompts to set up your project. Once it is set up, install the Crystalize.js library by running the following command: npm i crystalize.js You will also need to install helper libraries for converting an HTML file to an image, downloading the converted image, and getting icons. You can do this by running the following command: npm i html-to-image downloadjs react-icons Then, create “components” and “crystalizer” folders in the “src” directory. Additionally, create the following .jsx files in the “components” folder: canvas.jsx download-button.jsx edit-tool-list.jsx editor.jsx image-uploader.jsx range-input-field.jsx redo-button.jsx select-field.jsx sidebar.jsx text-field.jsx tool-list-item.jsx undo-button.jsx Lastly, create a “state.jsx” file in the “crystalizer” folder. At this point, your project folder structure should look similar to this: // Folder structure ┣ public ┃ ┣ favicon.ico ┃ ┣ next.svg ┃ ┗ vercel.svg ┣ src ┃ ┣ components ┃ ┃ ┣ canvas.jsx ┃ ┃ ┣ download-button.jsx ┃ ┃ ┣ edit-tool-list.jsx ┃ ┃ ┣ editor.jsx ┃ ┃ ┣ image-uploader.jsx ┃ ┃ ┣ range-input-field.jsx ┃ ┃ ┣ redo-button.jsx ┃ ┃ ┣ select-field.jsx ┃ ┃ ┣ sidebar.jsx ┃ ┃ ┣ text-field.jsx ┃ ┃ ┣ tool-list-item.jsx ┃ ┃ ┗ undo-button.jsx ┃ ┣ crystalizer ┃ ┃ ┗ state.jsx ┃ ┣ pages ┃ ┃ ┣ api ┃ ┃ ┃ ┗ hello.js ┃ ┃ ┣ _app.jsx ┃ ┃ ┣ _document.jsx ┃ ┃ ┗ index.jsx ┃ ┗ styles ┃ ┃ ┣ Home.module.css ┃ ┃ ┗ globals.css ┣ .gitignore ┣ README.md ┣ jsconfig.json ┣ next-env.d.ts ┣ next.config.js ┣ package-lock.json ┣ package.json ┗ tsconfig.json After setting up the folders, we will open the “src/crystalizer/state.jsx” file and start exploring the Crystalize.js library. Setting up the Context API Since Crystalize.js does not provide global state management, we will set it up using the React Context API. To do this, add the following code to the “src/crystalizer/state.jsx” file: import { createContext, useContext } from ‘react’; // Initialize context const EditImageContext = createContext(null); // Context provider export const EditImageContextProvider = ({ children }) => { return (
Source link