missive / emoji-mart

🏪 One component to pick them all
https://missiveapp.com/open/emoji-mart
MIT License
8.38k stars 802 forks source link

React and Emoji-Mart onClickOutside weird issue #819

Open RoseannePeeters opened 1 year ago

RoseannePeeters commented 1 year ago

Hi all,

I wanted to create a emoji picker for my project. But I ran into this weird issue when implementing onClickOutside. Whenever you click the "<input type="image"..." for the first time, the picker gets successfully shown. After it is closed, you cannot open it anymore. I have figured out why it will not open anymore, but not why it is behaving like that.

It doesn't open anymore because: First handleEmojiClick is ran, then handleClickOutside. handleClickOutside should not even happen in the first place since it is not rendered at the time. Console logs the following order of method calls (these are the first 4 clicks on the input type image:

running emoji click
running emoji click
running outside click
running emoji click
running outside click

This is the full code:

import React, { useState } from 'react'
import emojiPickerIcon from "../../assets/emojiPicker.png";
import emojiPickerPickedIcon from "../../assets/emojiPickerPicked.png";
import Picker from '@emoji-mart/react';

export default function DebugPage() {

    const [emojiPickerShown, setEmojiPickerShown] = useState(false);

    function handleClickOutside(e){
        if(emojiPickerShown){
            setEmojiPickerShown(false);
        }
    }

    function handleEmojiClick(e){
        e.preventDefault();
        setEmojiPickerShown(!emojiPickerShown)
    }

    return (
        <form>
            <input type="image" src={emojiPickerShown ? emojiPickerPickedIcon : emojiPickerIcon} onClick={handleEmojiClick} />
            { emojiPickerShown && <Picker onClickOutside={handleClickOutside} /> } 
        </form>
    )
}

This is very odd behaviour since that function should not run while the picker is not even rendered???

Could somebody explain this to me please?

Thanks in advance!

I tried a lot of debugging, getting it out the form, scaling down the code size, heck this is even a debug page.

xerox0213 commented 1 year ago

@RoseannePeeters Hey they certainly use a useEffect to add an event listener onClick to the window. Even if the component is not rendered, the event listener on the window still exists so that triggers your function handleClickOutside. I think that they have to removeEventListener after unmounting of Picker component. If you've found a solution let me know :).

YanceyOfficial commented 1 year ago

I have the same issue too.

paintoshi commented 9 months ago

Try e.stopPropagation() instead of e.preventDefault(). That worked for me.