Another super amazing feature here is to watch for a property of the atom's value
if it's defined as an object.
import React from "react";
import { atom, Atom } from "@mongez/react-atom";
type User = {
name: string;
email: string;
age: number;
};
const userAtom = atom<User>({
key: "user",
default: {},
});
Now let's create a component to display the user's name and email.
import React from "react";
import { userAtom } from "~/src/atoms";
export default function User() {
const user = userAtom.useValue();
return (
<>
<h1>User</h1>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
</>
);
}
Now let's update the user's name from another component.
import React from "react";
import { userAtom } from "~/src/atoms";
export default function UserForm() {
const [user, setUser] = userAtom.useState();
return (
<>
<h1>User Form</h1>
<input
type="text"
value={user.name}
onChange={(e) => setUser({ ...user, name: e.target.value })}
/>
<input
type="text"
value={user.email}
onChange={(e) => setUser({ ...user, email: e.target.value })}
/>
</>
);
}
This is great, but what if we want to have a component that will be rerendered only when the user's name changes, not the email, here we can use atom.useWatcher
to watch for a specific property of the atom's value.
import React from "react";
import { userAtom } from "~/src/atoms";
export default function User() {
const name = userAtom.useWatcher("name");
return (
<>
<h1>User</h1>
<p>Name: {name}</p>
</>
);
}
Now when the name
property is changed, this component will be rerendered automatically, otherwise it won't.
To listen to atom when it is reset, use onReset
method.
// anywhere in your app
import { currencyAtom } from "~/src/atoms";
currencyAtom.onReset((atom) => {
//
});
This will be triggered after the update event is triggered
Using atom.use will merge both useValue
and useWatcher
methods into one.
If the use
received a parameter, then it will be watching for the given property change, otherwise it will watch for the entire atom's value change.
Starting from version 2 and above, atom.use will be the recommended way to watch for atom's value changes for single property atoms instead of useWatcher as useWatcher will be removed in the next release.
type User = {
name: string;
age: number;
position: "developer" | "designer" | "manager";
notifications: number;
};
const userAtom = atom<User>({
key: "user",
default: {
name: "Hasan",
age: 25,
position: "developer",
},
});
// now in any component
import userAtom from "./userAtom";
export function Header() {
const notifications = userAtom.use("notifications");
return <header>{notifications}</header>;
}
This will only re-render the component when the notifications
property changes.
Using use
without any parameter will watch for the entire atom's value change.
type User = {
name: string;
age: number;
position: "developer" | "designer" | "manager";
notifications: number;
};
// now in any component
import userAtom from "./userAtom";
export function Header() {
const user = userAtom.useValue();
return <header>{user.notifications}</header>;
}
This will be rerendered when the entire atom's value changes.
type User = {
name: string;
age: number;
position: "developer" | "designer" | "manager";
notifications: number;
};
// now in any component
import userAtom from "./userAtom";
export function Header() {
const notifications = userAtom.use("notifications"); // will return number, and Typescript will complain if you try to use other properties
return <header>{notifications}</header>;
}
Instead of passing the whole object to the setUser
function, we can pass only the key we want to change using atom.change
function.
import React from "react";
import { userAtom } from "~/src/atoms";
export default function UserForm() {
const [user, setUser] = userAtom.useState();
return (
<>
<h1>User Form</h1>
<input
type="text"
value={user.name}
onChange={(e) => userAtom.change("name", e.target.value)}
/>
<input
type="text"
value={user.email}
onChange={(e) => userAtom.change("email", e.target.value)}
/>
</>
);
}
This will change only the given key in the atom's value, and trigger a component rerender if the atom's value is used in the component.
Please note that
change
method callsupdate
method under the hood, so it will generate a new object.
Wait for more, to be continued !