Write Only atoms

With the help of writeOnly atoms you can modify the atoms it relies on. It's basically a two-way data binding, changing the derived atom also changes the parent atom and vice-versa, so use these atoms very carefully.

const textAtom = atom('write only atoms') const uppercase = atom(null, (get, set) => { set(textAtom, get(textAtom).toUpperCase()) })

The first value of the callback is always be null and second is the function to modify the atom value. Let's take a more practical use case of write-only atoms.

Here we define a dotsAtom which is an atom of positions of points we draw on the canvas and a drawing atom.

const dotsAtom = atom([]); // true when we drawing on canvas const drawingAtom = atom(false);

The handleMouseDownAtom and handleMouseUpAtom are two write-only atom that we use to set the value of drawing atom and handleMouseMoveAtom is a write-only atom which adds the position of new points to the dotsArray atom when we drawing on the canvas.

const handleMouseMoveAtom = atom( null, (get, set, update: Point) => { if (get(drawingAtom)) { set(dotsAtom, (prev) => [...prev, update]); } } );

Note: You must be thinking that why we not updating the atoms value directly, why we use a write-only atom to update it's value. Well updating the value using the write-only atom prevents the extra rerenders in our app.

import { atom, useAtom } from "jotai";

const dotsAtom = atom([]);

const drawingAtom = atom(false);

const handleMouseDownAtom = atom(
  null,
  (get, set) => {
    set(drawingAtom, true);
  }
);

const handleMouseUpAtom = atom(null, (get, set) => {
  set(drawingAtom, false);
});

const handleMouseMoveAtom = atom(
  null,
  (get, set, update: Point) => {
    if (get(drawingAtom)) {
      set(dotsAtom, (prev) => [...prev, update]);
    }
  }
);

const SvgDots = () => {
  const [dots] = useAtom(dotsAtom);
  return (
    <g>
      {dots.map(([x, y], index) => (
        <circle cx={x} cy={y} r="2" fill="#aaa" key={index} />
      ))}
    </g>
  );
};

const SvgRoot = () => {
  const [, handleMouseUp] = useAtom(
    handleMouseUpAtom
  );
  const [, handleMouseDown] = useAtom(
    handleMouseDownAtom
  );
  const [, handleMouseMove] = useAtom(
    handleMouseMoveAtom
  );
  return (
    <svg
      width="100vw"
      height="100vh"
      viewBox="0 0 100vw 100vh"
      onMouseDown={handleMouseDown}
      onMouseUp={handleMouseUp}
      onMouseMove={(e) => {
        handleMouseMove([e.clientX, e.clientY]);
      }}
    >
      <rect width="100vw" height="100vh" fill="#eee" />
      <SvgDots />
    </svg>
  );
};

const App = () => (
  <>
    <SvgRoot />
  </>
);

export default App;

Open on CodeSandbox