Core components
Client core
Hyperflux state management
22 min
overview hyperflux is the primary state management system used in the ir engine client core it provides a centralized approach to managing application data and ensuring that the user interface stays synchronized with that data by implementing a reactive pattern, hyperflux enables different parts of the application to respond automatically to data changes, creating a consistent and responsive user experience this chapter explores the concepts, implementation, and usage of hyperflux within the ir engine client core concepts state management state management refers to how an application handles and maintains its data over time in a complex application like the ir engine client, there are many pieces of information that need to be tracked user authentication status and profile information ui preferences (theme settings, language, etc ) current application view or route active dialogs or modals real time data from server connections local user interactions and temporary states without a structured approach to managing this data, applications can become difficult to maintain as the state becomes scattered across different components, leading to inconsistencies and bugs centralized state hyperflux implements a centralized state management pattern where all application state is stored in a central repository components access this state through a standardized api state changes follow a predictable pattern ui components automatically update when relevant state changes this approach provides several benefits predictable data flow easier debugging and state inspection consistent state access patterns automatic ui updates when data changes implementation defining state the first step in using hyperflux is defining a state object using the definestate function // example defining a theme preference state import { definestate } from '@ir engine/hyperflux'; export const themepreferencestate = definestate({ name 'themepreferencestate', // unique identifier initial { darkmodeenabled false // initial value } }); this code imports the definestate function from hyperflux creates a new state definition with a unique name specifies the initial value for this state exports the state definition for use throughout the application the definestate function registers this state with the hyperflux system, making it available for components to access and modify reading state components can access state using hooks like usemutablestate (for react components) or functions like getstate (for non react code) // example reading state in a react component import { usemutablestate } from '@ir engine/hyperflux'; import { themepreferencestate } from ' /themepreferencestate'; function themetogglebutton() { // access the theme state const themeprefs = usemutablestate(themepreferencestate); // read the current value const isdarkmodeon = themeprefs darkmodeenabled value; return ( \<button> turn dark mode {isdarkmodeon ? 'off' 'on'} \</button> ); } this component imports the necessary functions and state definition uses usemutablestate to access the theme preferences reads the current value of darkmodeenabled renders a button with text based on the current state when using usemutablestate , the component automatically re renders whenever the accessed state changes, ensuring the ui stays in sync with the data modifying state to change state values, components use functions like getmutablestate and methods like set() // example modifying state import { getmutablestate } from '@ir engine/hyperflux'; import { themepreferencestate } from ' /themepreferencestate'; function handlethemetoggleclick() { // get a mutable reference to the state const themeprefs = getmutablestate(themepreferencestate); // read the current value const currentmode = themeprefs darkmodeenabled value; // set the new value (toggle it) themeprefs darkmodeenabled set(!currentmode); console log('dark mode is now ', themeprefs darkmodeenabled value); } this function gets a mutable reference to the theme state reads the current value of darkmodeenabled sets a new value by toggling the current value logs the new state for debugging when set() is called, hyperflux updates the state and notifies all components that are using this state, causing them to re render with the new value reactivity system the core of hyperflux is its reactivity system, which ensures that ui components automatically update when the state they depend on changes how reactivity works the reactivity system follows these steps registration when a state is defined with definestate , hyperflux registers it in its central system subscription when a component uses usemutablestate to access a state, it subscribes to changes for that specific state notification when state is modified with set() , hyperflux updates the value in its central store identifies all subscribers for that state notifies each subscriber that the state has changed triggers re renders of affected components this sequence diagram illustrates the process sequencediagram participant user as user (clicks toggle) participant togglebuttoncode as button click handler participant hyperflux as hyperflux core participant themestate as themepreferencestate participant uicomponent as ui component user >>togglebuttoncode clicks "toggle dark mode" togglebuttoncode >>hyperflux requests to update themestate ( set(true)) hyperflux >>themestate updates darkmodeenabled to true themestate >>hyperflux confirms update hyperflux >>uicomponent notifies themestate changed! uicomponent >>themestate reads new darkmodeenabled value (true) uicomponent >>uicomponent re renders with dark background this reactive approach eliminates the need for manual ui updates when data changes, reducing bugs and simplifying code advanced usage complex state structures hyperflux can manage complex nested state structures // example complex state with nested objects export const userprofilestate = definestate({ name 'userprofilestate', initial { personal { name '', email '', avatar '' }, preferences { notifications { email true, push false, inapp true }, privacy { showonline true, allowmessages 'friends' // 'all', 'friends', 'none' } }, statistics { lastlogin null, totalsessions 0, averagesessiontime 0 } } }); when working with nested structures, you can access nested properties userprofile preferences privacy showonline value update nested properties userprofile preferences privacy showonline set(false) update multiple properties userprofile personal merge({ name 'alice', email 'alice\@example com' }) state actions for more complex state updates, you can define actions within the state definition // example state with actions export const counterstate = definestate({ name 'counterstate', initial { count 0 }, // actions are functions that modify the state increment () => { const state = getmutablestate(counterstate); state count set(state count value + 1); }, decrement () => { const state = getmutablestate(counterstate); state count set(state count value 1); }, reset () => { const state = getmutablestate(counterstate); state count set(0); } }); // usage counterstate increment(); // increases count by 1 counterstate decrement(); // decreases count by 1 counterstate reset(); // resets count to 0 actions encapsulate state modification logic, making it easier to maintain and test state composition for complex applications, you can compose multiple state definitions // example composing multiple states import { userprofilestate } from ' /userprofilestate'; import { themepreferencestate } from ' /themepreferencestate'; import { notificationstate } from ' /notificationstate'; function usersettingspage() { // access multiple states const userprofile = usemutablestate(userprofilestate); const themeprefs = usemutablestate(themepreferencestate); const notifications = usemutablestate(notificationstate); // component logic using all three states // } this approach allows you to organize state logically while still accessing it easily where needed real world examples let's examine some real examples from the ir engine client codebase modal state management the modalstate manages pop up windows (modals) in the application // simplified from src/common/services/modalstate tsx import { definestate, getmutablestate } from '@ir engine/hyperflux'; // define the shape of modal data interface modaldata { element jsx element; id string; } export const modalstate = definestate({ name 'ee client modalstate', initial { modals \[] as modaldata\[] }, // action to open a modal openmodal (elementcontent jsx element) => { const modals = getmutablestate(modalstate) modals; const id = generateuniqueid(); modals merge(\[{ element elementcontent, id }]); return id; }, // action to close a modal closemodal (id string) => { const state = getmutablestate(modalstate); const currentmodals = state modals value; const updatedmodals = currentmodals filter(modal => modal id !== id); state modals set(updatedmodals); } }); this state maintains a list of active modals provides actions to open and close modals generates unique ids for each modal updates the state when modals are added or removed theme service the themeservice manages application themes (like light/dark mode) // simplified from src/common/services/themeservice tsx import { usemutablestate, definestate, getmutablestate } from '@ir engine/hyperflux'; import { useeffect } from 'react'; // define the theme state export const themestate = definestate({ name 'ee client themestate', initial { theme 'light' // 'light' or 'dark' }, // action to toggle the theme toggletheme () => { const state = getmutablestate(themestate); const currenttheme = state theme value; state theme set(currenttheme === 'light' ? 'dark' 'light'); } }); // react hook to apply the theme export const usethemeprovider = () => { const themestate = usemutablestate(themestate); const currenttheme = themestate theme value; useeffect(() => { // apply theme to document document body classlist remove('light theme', 'dark theme'); document body classlist add(`${currenttheme} theme`); // update meta theme color for mobile browsers const metathemecolor = document queryselector('meta\[name="theme color"]'); if (metathemecolor) { metathemecolor setattribute( 'content', currenttheme === 'dark' ? '#121212' '#ffffff' ); } }, \[currenttheme]); return { currenttheme, toggletheme themestate toggletheme }; }; this example demonstrates defining a theme state with light/dark options creating an action to toggle between themes using a react hook to apply the theme to the document returning the current theme and toggle function for components to use benefits of hyperflux hyperflux provides several key advantages for the ir engine client centralized state management all application state is managed in a consistent way reactive updates ui components automatically update when state changes predictable data flow state changes follow a clear pattern separation of concerns state logic is separated from ui components improved maintainability state is organized into logical domains easier debugging state can be inspected and tracked more easily reduced boilerplate less code needed to manage state and ui updates these benefits make hyperflux an essential foundation for the ir engine client architecture next steps with an understanding of how hyperflux manages application state, the next chapter explores how the client communicates with the server to retrieve and send data using feathersjs next feathersjs api & real time services docid\ nzkmudfdxfxilwah4peko