🕵️ SicherheitslückenWhat continuous operational resilience looks like under DORA(09.09.2026 um 17:53 Uhr)
🔧 AI Nachrichten OpenAI seeks tougher AI rules. CIOs may feel the ripple effects(10.09.2026 um 12:11 Uhr)
🔧 AI Nachrichten Mistral valued at €21bn after €3bn Series D funding round(08.09.2026 um 10:19 Uhr)
🪟 Windows TippsWindows XP's Cursor Indicator Is Getting a Windows 11 Refresh(25.08.2026 um 13:00 Uhr)
🕵️ SicherheitslückenWhat continuous operational resilience looks like under DORA(09.09.2026 um 17:53 Uhr)
🔧 AI Nachrichten OpenAI seeks tougher AI rules. CIOs may feel the ripple effects(10.09.2026 um 12:11 Uhr)
🔧 AI Nachrichten Mistral valued at €21bn after €3bn Series D funding round(08.09.2026 um 10:19 Uhr)
🪟 Windows TippsWindows XP's Cursor Indicator Is Getting a Windows 11 Refresh(25.08.2026 um 13:00 Uhr)

🔧 Programmierung 🕛 vor 2 Jahren 25 Min Lesezeit
0

Comparing TypeScript state management solutions

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Written by in our React and React Native projects. The React Redux library allows us to seamlessly integrate the Redux state management tool with React apps. Meanwhile, Redux Toolkit further simplifies the configuration and usage of Redux in our projects.



Redux has many features and benefits, especially when so we can inspect the store while developing. We will implement the counterReducer later in this tutorial.



Once the store is created, we can make it available to our Redux Toolkit components by putting a React Redux <Provider> around our application in src/index.tsx. Let’s import the Redux store we just created, add the <Provider> in the <App> component, and pass the store as a prop:




CODE
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';

import { App } from './App';
import store from './lib/store';

const root = createRoot(document.getElementById('app'));

root.render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>
);









Create a Redux state slice



Let’s add a new file named counterSlice.ts in the src/lib/features/counter/ directory. In this file, let’s bring in the createSlice API from the Redux Toolkit.



To make a slice, we should give it a name, an initial state, and one or more reducers to determine how the state can change. Once the slice is created, we can export the Redux action creators it generates and the entire slice's reducer function.



With Redux Toolkit's createSlice and createReducer, we can write our state updates like we are making changes directly, even though Redux demands immutable updates:




CODE
import { createSlice } from '@reduxjs/toolkit';

export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
},
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;






The code above sets up a simple counter in a React application and defines a Redux state slice to manage the counter’s state.






Use Redux state and actions in React components



Now, we can use the React Redux hooks to let React components interact with the Redux store. We can read data from the store using useSelector and dispatch actions using useDispatch.



Let’s modify our App.tsx component like below to show the counter and increase and decrease its value:




CODE
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { decrement, increment } from './lib/features/counter/counterSlice';
import { IRootReducer } from './lib/store';

export function App() {
const count = useSelector<IRootReducer, number>(
(state) => state.counter.value
);
const dispatch = useDispatch();

return (
<div>
<div>
<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
Increment
</button>
<span>{count}</span>
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
Decrement
</button>
</div>
</div>
);
}






The Counter component we set up here interacts with the counterSlice component we created previously to access the current state of the counter slice and display and modify its values in the component.



You can check out this example in .






MobX with MobX React Lite



MobX is a well-tested library for managing states in a simple and scalable way using functional reactive programming. The idea is to keep the code minimal and straightforward.



If we want to update a field in a record, we can use a regular JavaScript assignment, and MobX will update everything else automatically. It also ensures efficient rendering and tracking of changes to our data at runtime to only update what's necessary, saving us from manual optimizations like memorization.



What's remarkable about MobX is its flexibility. We can handle our application state independently of any UI framework. This makes the code more modular, portable, and easy to test. So, in a nutshell, MobX helps us manage state effortlessly and efficiently in your applications.



MobX is versatile — it works in various environments, like browsers and Node.js projects that support ES5.



Regarding .



When we wrap the TimerView React component with the observer, it understands that it needs to update whenever the timer.secondsPassed changes, even if we don't explicitly mention it. Thanks to the reactivity system in MobX, our component will automatically re-render whenever that specific field is updated.



So, whenever we click on the button or use setInterval, it triggers an action — Timer.increase or myTimer.reset — updating the observable state, or myTimer.secondsPassed. This update then propagates smoothly to all the computations and side effects like TimerView that rely on those changes: .






NgRx



for help if you are new to Angular or Angular CLI. After initializing a new Angular project and installing our @ngrx/store library, we can proceed to the next stage.



Note that we’re implementing our simple NgRx state management example using .



Let’s work on another counting example. Let’s create a new file, counter.actions.ts, in the src/app/ directory and paste the following code:




CODE
import { createAction } from '@ngrx/store';

export const increment = createAction('[Counter Component] Increment');
export const decrement = createAction('[Counter Component] Decrement');
export const reset = createAction('[Counter Component] Reset');






The above code describes unique events that are dispatched from components and services. Next, we’ll define a reducer function — src/app/counter.reducer.ts — to handle changes in the counter value based on the provided actions:




CODE
import { createReducer, on } from '@ngrx/store';
import { increment, decrement, reset } from './counter.actions';

export const initialState = 0;

export const counterReducer = createReducer(
initialState,
on(increment, (state) => state + 1),
on(decrement, (state) => state - 1),
on(reset, (state) => 0)
);






Now, let’s add the counterReducer in the app.config.ts:




CODE
**import { ApplicationConfig } from '@angular/core';

import { provideStore } from '@ngrx/store';
import { counterReducer } from './counter.reducer';

export const appConfig: ApplicationConfig = {
providers: [provideStore({
count: counterReducer
})],
};






Let’s create a new component called my-counter using the following command:




CODE
ng g c my-counter






This command should create all the files we need, including the my-counter.component.ts file and the my-counter.component.html file. Copy the following code into the my-counter.component.ts file:




CODE
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { increment, decrement, reset } from '../counter.actions';
import { CommonModule } from '@angular/common';

@Component({
selector: 'app-my-counter',
templateUrl: './my-counter.component.html',
standalone: true,
imports: [CommonModule],
})
export class MyCounterComponent {
count$: Observable<number>;
constructor(private store: Store<{ count: number }>) {
this.count$ = store.select('count');
}
increment() {
this.store.dispatch(increment());
}
decrement() {
this.store.dispatch(decrement());
}
reset() {
this.store.dispatch(reset());
}
}






Next, let’s copy the following code in the my-counter.component.html file:




CODE
<button (click)="increment()">Increment</button>
<div>Current Count: {{ count$ | async }}</div>
<button (click)="decrement()">Decrement</button>
<button (click)="reset()">Reset Counter</button>






Now, let’s add this new component in AppComponent. Paste the following code in your app.component.ts file:




CODE
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { MyCounterComponent } from './my-counter/my-counter.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, RouterOutlet, MyCounterComponent],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent {
title = 'angular-project';
}






Finally, declare it in the app template:




CODE
<h1>Hello World!</h1>
<app-my-counter></app-my-counter>






The code above sets up a simple counter in an Angular application using the NgRx Store for state management.



For more details, you can . It enables seamless state-sharing among components and pages. While the Composition API allows us to share global states easily in SPAs, it might expose our app to security vulnerabilities if it's rendered on the server side, making Pinia crucial.



Even in smaller applications, Pinia brings several advantages, including:




  • Devtools support

  • A timeline for action and mutation tracking

  • Stores conveniently appearing where they are used in components

  • Time travel for debugging

  • Hot module replacement for modifying stores without reloading the page

  • The ability to keep the existing state during development



Pinia also offers plugins to extend its features, robust TypeScript support, and compatibility with server-side rendering.



To use Pinia, you must first install it using your to see and interact with the demo. For more details, please , built by Meta. It lets you create a data-flow graph where you flow your shared states (atoms) through functions (selectors) and eventually reach your React components.



Some notable Recoil features include:




  • Introduces the concept of an "atom," which represents a piece of state. Atoms can be easily created and accessed, providing a simple and efficient way to manage the state

  • Provides selectors, which allow us to derive computed values from atoms. These can be used to create a derived state or perform calculations based on the current state. Atoms are like state units that your components can subscribe to, and selectors can transform this state synchronously or asynchronously

  • Designed to work well with TypeScript, providing type safety for your state. This includes defining the types of your atoms and selectors and enhancing the development experience

  • Supports asynchronous operations, allowing you to handle async data and side effects using asynchronous selectors or effects



Installing Recoil is pretty straightforward, just like the other packages. We can use any of our favorite package managers to install the state management library in our React app:




CODE
npm install recoil
# or using yarn
yarn add recoil
# or using bower
bower install --save recoil









Understanding RecoilRoot



Components with states that are managed by Recoil need the RecoilRoot component to appear somewhere in the parent tree. The RecoilRoot component is essential for creating the context for Recoil state management. Without adding this, the Recoil state management will not work.



An excellent place to put this component is in your root component, like so:




CODE
import {
atom,
RecoilRoot,
selector,
useRecoilState,
useRecoilValue,
} from 'recoil';

export const App = () => {
return (
<RecoilRoot>
<CharacterCounter />
</RecoilRoot>
);
};






In this example, we are building a character-counter example. We will take the text input and show the character length as output. We'll implement the CharacterCounter component in the following section.






The purpose of an atom in Recoil



An atom represents a piece of state. Atoms can be read and written from any component. Components that read the value of an atom are implicitly subscribed to that atom, so any atom updates will result in a re-render of all components subscribed to that atom:




CODE
const textState = atom({
key: 'textState',
default: '',
});






Usually in React, we use . For more details, you can — is an asynchronous state management library for React and React Native. It can handle tasks like data fetching, caching, synchronizing, and updating server state in your React apps.



While other state management solutions provide a way to view and update states across the application, React Query provides solutions to manage the data that we get from the API.



We can install React Query by running the following command:




CODE
npm i @tanstack/react-query
# or
yarn add @tanstack/react-query









Basic example using React Query for state management



We can fetch the data from an API using the useQuery Hook. Similarly, we can request any POST, PUT, PATCH, or DELETE operation using the useMutation Hook. Here is a simple example in the React App.tsx file, where we will fetch some todo data from a fake API:




CODE
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';

const queryClient = new QueryClient()

const API_ENDPOINT = `https://jsonplaceholder.typicode.com`;

const Todo = () => {
const { data } = useQuery({
queryKey: [`${API_ENDPOINT}/todos`],
queryFn: () => fetch(`${API_ENDPOINT}/todos`).then((res) => res.json()),
});
console.log(data);
return (
<div>
{(data || []).map((item) => (
<div key={item.id}>
<h4 style={{ lineHeight: '100%', marginBottom: 0 }}>{item.title}</h4>
<p>{item.completed ? 'Done' : 'Not Done Yet'}</p>
</div>
))}
</div>
);
};

export const App = () => {
return (
<QueryClientProvider client={queryClient}>
<Todo />
</QueryClientProvider>
);
};






The complete code is available in .






Jotai



Jotai is another state management library for React. Like Recoil, it takes an atomic approach to global React state management.



We can create a state by putting together "atoms," or pieces of state. The renders automatically get smarter based on what these atoms depend on.



This clever trick solves the problem of unnecessary re-renders in the React context, eliminating the need for memoization. It gives developers a smooth experience, similar to using signals while sticking to a clear and straightforward programming style, making it scalable.



To install Jotai in your project, simply use one of the commands below:




CODE
# npm
npm i jotai

# yarn
yarn add jotai

# pnpm
pnpm add jotai









Configuring Jotai for your framework



Adding the optional SWC or Babel plugin is recommended to enable React Fast Refresh support for the best developer experience specific to each framework. Let’s see some popular configuration options.



If you want to add the SWC plugin to a Next.js project, do the following:




CODE
# npm
npm install --save-dev @swc-jotai/react-refresh

# next.config.js
experimental: {
swcPlugins: [['@swc-jotai/react-refresh', {}]],
}






Meanwhile, you can add the Babel plugin to your Next.js project like so:




CODE
># .babelrc
{
"presets": ["next/babel"],
"plugins": ["jotai/babel/plugin-react-refresh"]
}






For Vite, you can add the SWC plugin to a React project with the code below:




CODE
# npm
npm install --save-dev @swc-jotai/react-refresh

# vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';

export default defineConfig({
plugins: [
react({
plugins: [['@swc-jotai/react-refresh', {}]],
}),
],
});






For Gatsby, you can add the Babel plugin with the code below:




CODE
# npm
npm install --save-dev babel-preset-gatsby

# .babelrc
{
"presets": ["babel-preset-gatsby"],
"plugins": ["jotai/babel/plugin-react-refresh"]
}

# gatsby-config.js
flags: {
DEV_SSR: false,
}









Basic example using Jotai for state management



Here is a basic example of . For more information, you can go through



  • : Full visibility into your web and mobile apps


    is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.



    In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.



    Try it for free.

    Vollständiger Original-Bericht
    Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
    ↗ Original-Artikel auf dev.to lesen
  • Wie bewertest du diesen Beitrag?
    1 Klick Feedback
    Teilen mit Netzwerk & Team:

    Community-Analysen & Experten-Meinungen 0

    Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
    Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
    Community Pulse: Relevanz-Einschätzung
    1 Klick Experten-Votum
    🔴 Akute Relevanz 0%
    🟡 In Evaluierung 0%
    🟢 Keine Auswirkung 0%
    Spannende Innovation 0%
    Verwandte Story-Cluster & Quellen (Vektor-KI)
    Port 8095 Engine
    1 Quelle
    Sam Altman calls GPT-6 Astra rollout ‘messy’ as enterprise users wait for access
    1 Quelle
    Swiss government explores replacing Microsoft 365 with open-source software
    1 Quelle
    What continuous operational resilience looks like under DORA
    Ähnliche Beiträge
    🔍 Verwandte News

    Auch interessante Nachrichten Comparing TypeScript state management solutions

    Thematisch verwandte Begriffe: Comparing, TypeScript, state, management · 6 Treffer

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...