Read Write atoms

These atoms are the combination of both read-only and write-only atoms.

const count = atom(1); export const readWriteAtom = atom((get) => get(count), (get, set) => { set(count, get(count) + 1); }, );

The first parameter is for reading and the second is for modifying the atom value. Since the readWriteAtom is capable of both reading and updating the original atom value, we can export readWriteAtom on its own and can hide the original atom in a smaller scope. This allows us to reduce the number of atoms in our app.

See the code for an example of how we can use only handleMouseMoveAtom to both read and update dotsAtom 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(
  (get) => get(dotsAtom),
  (get, set, update: Point) => {
    if (get(drawingAtom)) {
      set(dotsAtom, (prev) => [...prev, update]);
    }
  }
);

const SvgDots = () => {
  const [dots] = useAtom(handleMouseMoveAtom);
  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