[email protected]

Shared state and instant translations in Talent One

Talent One features share app state through one typed store, and the whole app switches between English and Vietnamese at once, with no reload. Used in over 100 files.

All work
lost_connection
enLost internet connection
viMất kết nối mạng
Used in
Talent One Employer and VietnamWorks Employer
Adoption
Over 100 Talent One files
Open source
@khanglvm/react 1.2.2 on npm

The same setup in every feature

Talent One Employer is split into feature packages such as job posting, candidate search, campaigns and the page builder. A job-posting form or a page editor shares its state across many components, and every screen needs English and Vietnamese text.

Plain React context rerenders every consumer when its value changes, and untyped dictionaries let a missing key or a missing Vietnamese string slip through. Each team was writing its own version of both, so I designed one shared version.

What a feature team gets

A feature package creates its own state store and translator hook from the shared factories, typed by the shape of its state and its dictionary. It points the translator hook at the language in the app-shell store, and from then on its text follows every language switch.

Any component can read one slice of the app-shell store, such as the signed-in employer or the language, and it rerenders only when that slice changes.

How one switch reaches every screen

The app shell keeps its state, the language included, in a single store. Components subscribe through useSyncExternalStore with a selector, and a cache compares each selected value with deepEqual, so an update elsewhere leaves them alone. Updates are Immer drafts, and their notifications are batched into one microtask.

Changing the language writes one field in that store. Translator hooks are memoized on the language, and each dictionary entry holds its English and Vietnamese text side by side, so the whole app rerenders in the other language with no reload and no dictionary fetch.

The app-shell store holds the language. Each feature package builds its own state and a translator hook memoized on the language from the shared factories. Components read one slice through a selector. Switching language writes one field and every translator hook re-reads it.

Four choices and their costs

  • Context only locates the store; components subscribe to it through selectors. A busy form need not rerender every field, but I own the subscriptions, the equality checks and the server-side lifetime. In 2026 I moved snapshot caches into the hook, because effect cleanup never runs on the server.
  • Each feature or page gets its own Provider and its own store, which suits feature packages and keeps server requests apart. A global store such as Zustand needs no Providers; I wanted Provider scoping, Immer drafts and per-update revert in one contract. I chose this on design grounds and did not benchmark it.
  • Every update returns a revert function built from Immer’s inverse patches. Optimistic UI can roll back a failed save without keeping an undo history. Unrelated writes survive a revert, but a later write to the same field can be overwritten.
  • Translations are plain typed objects with every language in each leaf. A missing Vietnamese string is a type error, and keys autocomplete with no code generation or build step. The libraries I looked at lacked typed object declarations or tied them to Next.js, while this one runs unchanged in the VietnamWorks microfrontends and in Talent One. Plurals and ICU formatting are out of scope.

Where it started and who keeps it running

I wrote the typed translator in April 2024 and the state store in July 2024, both in VietnamWorks Employer’s shared package. In January 2025 I brought them to LaUI, Talent One’s UI library, where feature teams adopted them. Teammates maintain the code built around them.

Over 100 Talent One files import them. A general version is public as @khanglvm/react, at 1.2.2 with about 215 downloads a month. Fewer rerenders follows from the design; I have not measured a rendering speedup.

PartTalent One files importing it
Translations102
Shared state30
Typed events10

In use today

  • Used in over 100 Talent One files.
  • The whole app switches between English and Vietnamese with no reload.
  • Published on npm as @khanglvm/react 1.2.2.
@khanglvm/react source

Keep exploring

Faster builds for Talent One EmployerRecruitment page builder