Observer class
Observer class is a tool that allows you to declare global state variables and update them from anywhere in your application.
In addition to updating state values, you can also observe them using Observer to be notified when they change.
By default, Rosma uses a single instance of the Observer class. However, you can use multiple instances of the Observer class to better manage your project. This will be explained in the next sections.
The Observer class provides several methods, which are listed below:
observer.get
The observer.get
method is used to retrieve values from the state. You can use this method to get one or more values simultaneously.
Getting a Single Value
To retrieve a single value from the state, you must pass the key of the variable as an argument to the get
method.
For example, suppose the value of the foo
in the state is equal to 'bar'
. In this case, you can retrieve the value of the foo
and assign it to a variable as follows:
import { observer } from 'rosma';
const foo = observer.get('foo');
console.log(foo); // bar
Getting Multiple Values
If you want to retrieve more than one value from the state, you must pass the desired keys as an array to the get
method. In this case, the value returned from the get
method is an object.
For example, suppose our state contains values of foo
equal to 'bar'
and baz
equal to 'qux'
. To retrieve the values of foo
and baz
at the same time, you can use the following code:
import { observer } from 'rosma';
const values = observer.get(['foo', 'baz']);
console.log(values); // { foo: 'bar', baz: 'qux' }
You can also destructure the returned object to assign each value to a separate variable, like this:
import { observer } from 'rosma';
const { foo, baz } = observer.get(['foo', 'baz']);
console.log(foo, baz); // 'bar', 'qux'
observer.set
The set
method is used to change or add one or more values in the state. When a value in the state is changed using the set
method, all components that use that value will be rerendered. However, it's also possible to change a value silently, without triggering a rerender of the components that use it.
Note that if you set a value silently, and a component using that value is later rerendered for any other reasons, the new value will be received from the state.
Demo
import { observer, useObserver } from 'rosma';
export function DisplayTime() {
const { time, setTime } = useObserver('');
return (
<div>
<p>Time is: {time}</p>
<Button onClick={() => setTime(getTime())}>
Update time with setter method
</Button>
<Button onClick={() => observer.set({ time: getTime() })}>
Update time with observer.set
</Button>
<Button
onClick={() => observer.set({ time: getTime() }, { silent: true })}
>
Update time silently
</Button>
</div>
);
}
function getTime() {
return new Date().toLocaleTimeString();
}
function Button(props) {
return <button {...props} style={{ display: 'block' }} />;
}
Time is:
In this example, the DisplayTime
component retrieves the time
value from the Observer
state using useObserver
and displays it in a paragraph element.
The component also includes three buttons that allow the user to update the time
value in different ways. The first button calls the setTime
method to update the value using the useObserver
hook. The second button calls the observer.set
method to update the value directly in the Observer
state. The third button calls the observer.set
method with the silent
option to update the value silently, without triggering a rerender of any components that use the time
value.
Modals Example
This code is a simple example of using global state management with the Observer tool. It allows the user to open and close modal components and displays them in the app.
app.tsx
The App
component is the entry point of the application. It contains a button that triggers the opening of a modal and renders the Modals
component that shows all open modals. The newModal
function is imported from actions.ts
to handle the opening of the new modal.
import Modals from './modals';
import { newModal } from './actions';
export function App() {
return (
<>
<button
onClick={() => newModal({ title: 'Modal title', body: 'Modal body' })}
>
Open Modal
</button>
<Modals />
</>
);
}
modals.tsx
The Modals
component uses the useObserver
hook to get the modals
array from the state, which holds the data for each open modal. The map
function is used to render a Modal
component for each open modal. The Modal
component is responsible for rendering the modal component with its title
, body
, and close
button.
import { useObserver } from 'rosma';
import { closeModal } from './actions';
export default function Modals() {
const { modals } = useObserver([]);
return modals.map((modal, index) => <Modal key={index} {...modal} />);
}
function Modal({ title, body, id }) {
return (
<div
style={{
backgroundColor: 'white',
boxShadow: '0 0 5px #ccc',
minWidth: '300px',
position: 'fixed',
left: '50%',
top: '50%',
transform: 'translate(-50%, -50%)',
borderRadius: '7px',
}}
>
<div
style={{
display: 'flex',
padding: '10px',
borderBottom: '1px solid #ccc',
gap: '5px',
}}
>
<span>{title}</span>
<span>#{id}</span>
<div style={{ flex: 1 }} />
<button onClick={() => closeModal(id)}>x</button>
</div>
<div style={{ padding: '10px' }}>{body}</div>
</div>
);
}
actions.ts
The actions
file exports two functions: newModal
and closeModal
. Both of these functions use the observer
instance provided by the Rosma library to get and set the modals
array in the global state. The newModal
function creates a new modal object with a unique id
, title
, and body
and adds it to the modals
array. The closeModal
function filters out the modal with the given id
from the modals
array.
import { observer } from 'rosma';
export function newModal({ title, body }) {
const modals = observer.get('modals') || [];
const modal = {
id: modals.length + 1,
title,
body,
};
modals.push(modal);
observer.set({ modals });
}
export function closeModal(id) {
const modals = observer.get('modals') || [];
observer.set({ modals: modals.filter((modal) => modal.id !== id) });
}
Demo
observer.state
Returns the current value of the state.
As mentioned previously, all variables in the state are stored in lowercase, while the names retrieved from the state values are not case-sensitive.
Note that mutating the state using observer.state
does not re-render the components or trigger listeners.
import { observer } from 'rosma';
observer.set({ foo: 'bar' });
console.log(observer.state.foo); // "bar"
observer.isValid
observer.get
checks whether a given key
exists in the state or not. it gets a string as the key
and determines whether that variable is defined in the state or not.
import { observe } from 'rosma';
observer.isValid('myVariable'); // false
observer.set({ myVariable: 'something' });
observer.isValid('myVariable'); // true
observer.subscribe
The subscribe
method is utilized to monitor changes in one or more variables in the state
. This method requires two input parameters:
-
The desired
key
orkeys
that you want to observe. -
A
listener
that will execute when the desiredkey
orkeys
have changed.
The method returns an unsubscribe
function, allowing you to stop listening to state changes when needed. It can be used within useEffect
or outside of your React component, depending on your needs. If you need to monitor the changes of multiple variables at the same time, you can provide them as an array
and pass the as the first parameter. However, note that in this case, the desired values will be passed to the listener function as an object
.
We will talk more about subscribe in the next sections.
Demo
import { observer, useObserver } from 'rosma';
const unsubscribe = observer.subscribe('myVar', listener);
function listener(myVar) {
alert('myVar changed! ' + myVar);
}
export function ObserverTest() {
const { setMyVar } = useObserver();
return (
<>
<button onClick={() => setMyVar(new Date())}>Click me</button>
<button onClick={unsubscribe}>Unsubscribe</button>
</>
);
}
This code imports the observer
and useObserver
from the rosma
library. It then subscribes
to changes of a variable named myVar by calling observer.subscribe
and passing in the name of the variable and a listener function that will be called whenever the variable changes.
The ObserverTest
component uses useObserver
to get the setMyVar
function, which can be called to update the value of myVar
. The component renders a button that, when clicked, calls setMyVar
with a new date object as its argument. When myVar
changes, the listener
function is called and an alert is displayed with the updated value of myVar
.
If the user clicks on the unsubscribe
button. The unsubscribe
method is executed and the listener
function is no longer called with the myVar
changes.
Keywords: Observer, global state variables, update state, observe state, multiple instances, observer.get, observer.set, observer.isValid, observer.subscribe, retrieve values, get single value, get multiple values, change or add values, silently, Demo, modals example, app.tsx, modals.tsx
Previous: useObserver hook
Next: Multiple observers