Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to avoid extra rerender? #26

Closed
michael-land opened this issue Sep 10, 2020 · 10 comments
Closed

How to avoid extra rerender? #26

michael-land opened this issue Sep 10, 2020 · 10 comments
Labels
has snippet This issue includes code snipppets as solutions or workarounds help wanted Please someone help on this

Comments

@michael-land
Copy link

michael-land commented Sep 10, 2020

with Jotai, the <FakeCard /> will re-render whenever editId changed, but Recoil.js does not because i can select only setter function. How to achieve the same behavior with Jotai?

Recoil

import React from 'react';
import { atom, useRecoilState, useSetRecoilState } from 'recoil';

const editIdAtom = atom<number | null>({
  key: `editIdAtom`,
  default: null,
});

function FakeCard() {
  const setEditId = useSetRecoilState(editIdAtom);
  const handleClick = React.useCallback(
    (e: React.MouseEvent<HTMLAnchorElement>) => {
      setEditId(1);
    },
    [setEditId]
  );
  return (
    <div>
      <a onClick={handleClick}>toggle</a>
      <FakeModal />
    </div>
  );
}

function FakeModal() {
  const [editId, setEditId] = useRecoilState(editIdAtom);
  const handleClose = React.useCallback(() => {
    setEditId(null);
  }, [setEditId]);

  return editId ? <span>editing {editId}</span> : null;
}

Jotai

import React from 'react';
import { atom, useAtom } from 'jotai';

const editIdAtom = atom<number | null>(null);

function FakeCard() {
  const [,setEditId] = useAtom(editIdAtom);
  const handleClick = React.useCallback(
    (e: React.MouseEvent<HTMLAnchorElement>) => {
      setEditId(1);
    },
    [setEditId]
  );
  return (
    <div>
      <a onClick={handleClick}>toggle</a>
      <FakeModal />
    </div>
  );
}

function FakeModal() {
  const [editId, setEditId] = useAtom(editIdAtom);
  const handleClose = React.useCallback(() => {
    setEditId(null);
  }, [setEditId]);

  return editId ? <span>editing {editId}</span> : null;
}
@dai-shi
Copy link
Member

dai-shi commented Sep 10, 2020

Hi, thanks for opening up the issue.
Jotai core doesn't provide useSetRecoilState equivalent. Instead, we use write-only atoms.

const editIdAtom = atom<number | null>(null);
const setEditIdAtom = atom(null, (_get, set, x: number) => set(editIdAtom, x));

  const [,setEditId] = useAtom(setEditIdAtom);

Now, I wonder if we can build a generalized hook.

const useSetAtom = (anAtom) => {
  const writeOnlyAtom = useMemo(() => atom(null, (get, set, x) => set(anAtom, x)), [anAtom]);
  return useAtom(writeOnlyAtom)[1];
};

@dai-shi dai-shi added the has snippet This issue includes code snipppets as solutions or workarounds label Sep 11, 2020
@cevr
Copy link

cevr commented Sep 13, 2020

I think a set of utility hooks for common patterns (like the one mentioned above) would add that icing on top of a wonderful cake

@dai-shi
Copy link
Member

dai-shi commented Sep 13, 2020

@cevr Yeah, I agree. And, I want to separate them from the core. Let me start with this one.

The utility hooks can get big. I need someone to volunteer to help it, especially for documentation & examples.

@dai-shi dai-shi added the help wanted Please someone help on this label Sep 13, 2020
@dai-shi
Copy link
Member

dai-shi commented Sep 13, 2020

https://www.npmjs.com/package/jotai/v/0.5.0 published which includes #35
Please report if any issue is found. Closing this.

@dai-shi dai-shi closed this as completed Sep 13, 2020
@liby
Copy link
Contributor

liby commented Jul 16, 2021

const editIdAtom = atom<number | null>(null);
const setEditIdAtom = atom(null, (_get, set, x: number) => set(editIdAtom, x));

const [,setEditId] = useAtom(setEditIdAtom);

I have two questions about this part of the code:

  1. Writing it this way does not avoid extra rerender, so what is the point?
  2. How does it differ from using const [, setEditId] = useAtom(editIdAtom); directly?

@dai-shi Looking forward to your reply

@dai-shi
Copy link
Member

dai-shi commented Jul 16, 2021

I don't know why you think it doesn't avoid extra rerenders, but here's the example:
https://codesandbox.io/s/empty-wildflower-6kcmf?file=/src/App.js

@liby
Copy link
Contributor

liby commented Jul 16, 2021

@dai-shi
It should be a problem with the code I wrote during testing, causing me to have the wrong perception. I apologize for asking questions without verifying it. Thank you for correcting me.

@liby
Copy link
Contributor

liby commented Jul 16, 2021

@dai-shi
Follow up report, the reason for my misunderstanding is that not removing primitive atoms when using write-only atoms within a component.
Example: https://codesandbox.io/s/vigilant-hertz-bqb0r

@lili21
Copy link

lili21 commented Apr 21, 2022

is there any different between useSetAtom and useUpdateAtom

@dai-shi
Copy link
Member

dai-shi commented Apr 21, 2022

No. 😁

export { useSetAtom as useUpdateAtom } from 'jotai'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has snippet This issue includes code snipppets as solutions or workarounds help wanted Please someone help on this
Projects
None yet
Development

No branches or pull requests

5 participants