Code Monkey home page Code Monkey logo

Comments (8)

TKasperczyk avatar TKasperczyk commented on June 20, 2024 1

Thank you for your comprehensive explanation. I appreciate the suggested strategies on how to handle the issue.
I believe the most consistent approach would be to make the user responsible for handling re-renders. In other words, you should shift towards utilizing the standard export default React.memo(EmojiPicker) strategy instead of the current memoization logic (where you ignore non-primitive prop changes). This means that EmojiPicker would re-render whenever the parent renders due to non-primitive prop changes.
However, this is precisely why we should use React.useCallback, a standard that gracefully passes the responsibility of limiting unnecessary re-renders to the user. Here's what I mean:

// ...
const onEmojiClick = React.useCallback((emoji: EmojiClickData) => {
    alert(`Current state: ${myState}`);
}, [myState]);
// ...

<EmojiPicker onEmojiClick={onEmojiClick} />

Notably, this triggers the picker to only re-render when the state value changes, and not every time the parent does. But if users would still like to limit re-renders of the picker even further, they are welcome to use refs instead by having an empty dependency array in the useCallback declaration, with myState as a ref.

This approach maintains what I believe most users anticipate when interacting with external libraries. While it's true that it may not be suitable for every scenario, it has the advantage of aligning with widespread, standardized practices.
Nevertheless, if I were to choose between one of the proposed strategies, I'd go for the first one - a mem-key prop that would allow us to manually trigger re-renders of the EmojiPicker component.

Let me know if you have any comments or need further clarification on the proposed approach.

from emoji-picker-react.

ealush avatar ealush commented on June 20, 2024 1

Sorry for not responding earlier. @TKasperczyk, It's been quite difficult to concentrate on OSS work during the current war situation.

@cr0ybot, as a workaround until I introduce one of these options that I described above (or go with @TKasperczyk's suggestion), one of these could work:

  1. use refs
  2. do not reference the state in your onEmojiClick function, but rather only set the next state using a callback function
  3. add a key property to the picker. Its value should be your current emoji state.

from emoji-picker-react.

ealush avatar ealush commented on June 20, 2024 1

@cr0ybot try 4.5.3. I just releaesd it a few minutes ago. It is possible that it will solve it for you, if not, can you share with me a repro sandbox? I will try to get this fixed.

from emoji-picker-react.

ealush avatar ealush commented on June 20, 2024

Hey @TKasperczyk, as you noted correctly, the most straightforward workaround is to use refs. But, as you also mentioned, it is cumbersome and counter intuitive.

I'll shed some light on what's going on, and let's try to find together a solution for it that would be viable for you.

The reason onEmojiClick gets an outdated state reference is the internal memoization of the picker. The picker uses memeoizeation because otherwise, each state update outside of the picker would trigger full rerender of all emojis (1000s of elements), which would cause significant lag. Instead, I memoize by all primitive props. The others are not factored in (cannot compare a function, for example), so state update outside of the picker do not change the onEmojiClick reference.

There are two ways to handle it, as I see it:

  1. Simple, requires additional prop:
    Add another prop that serves as your external mem-key, it will trigger an update each time it changes.
    It is the simples to add on my end, but would be harder to discover, and require yet another step on your end.

  2. More complex, without API changes
    Store all non-primitives in an internal ref, and pass them down regardless of memoization stage. This is slightly more complex on the internal picker implementation, and the main drawback is that it might miss some cases (as you experience now).

How would you, as a consumer, want to use it?

from emoji-picker-react.

cr0ybot avatar cr0ybot commented on June 20, 2024

I was pulling my hair out trying to figure out why I couldn't build an additive string of emojis with onEmojiClick, even using useCallback.

Is there really no way to update the internal ref of onEmojiClick while also not rerendering the entire component? Or is it just that you want a holistic solution for all props instead of only onEmojiClick?

from emoji-picker-react.

ealush avatar ealush commented on June 20, 2024

@TKasperczyk
I agree that this would give more granular control to the consumer side, and this is also something that's quite standard, but I am looking at it slightly differently.

Essentially, what you're describing is a prerequisite to using the picker, meaning, everyone who wants to use the picker will have to do this. 100% boilerplate code that all consumers need to add. In that case, I want to reduce that and have it a part of the picker.
As you noted, adding the ref on your end solves it, but it is icky, because it requires working around the component. I imagine having everyone use useCallback as a similar thing.

I think that regardless of what I pick as an api change I will make that internal ref thing that I mentioned to unbreak most existing use-cases, and this will give us some time to discuss a longer-term solution.

from emoji-picker-react.

cr0ybot avatar cr0ybot commented on June 20, 2024

@ealush Thanks for you work on this, it works now with useCallback!

from emoji-picker-react.

ealush avatar ealush commented on June 20, 2024

Closing, since this is no longer an issue

from emoji-picker-react.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.