Mongez React Atom Part-3

Mohamed Eltahawy
Nov 22
2 min read
post_comment0 Comments
post_like0 Likes

#Watch form object's key changes

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.

#On Atom Reset

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>;
}

#Changing only single key in the atom's value

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 calls update method under the hood, so it will generate a new object.

Wait for more, to be continued !

You are not logged in.