missive / emoji-mart

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

React component throws React.forwardRef error #884

Open excelwebzone opened 9 months ago

excelwebzone commented 9 months ago

When using @emoji-mart/reac I'm getting an error:

chunk-YTQVGCO2.js?v=4616d38d:521 Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Look like you need to upgrade the component. Here is a new version:

// @ts-nocheck
import React, { useEffect, useImperativeHandle, useRef } from 'react'
import { Picker } from 'emoji-mart'

const EmojiPicker = React.forwardRef((props, ref) => {
  const pickerRef = useRef(null)

  if (pickerRef.current) {
    pickerRef.current.update(props)
  }

  useEffect(() => {
    pickerRef.current = new Picker({ ...props })

    return () => {
      pickerRef.current = null
    }
  }, [])

  // Expose methods or properties via the ref
  useImperativeHandle(ref, () => ({
    update: (newProps) => pickerRef.current?.update(newProps),
    // Add more methods or properties as needed
  }), [props])

  return <div ref={ref} />
})

export default EmojiPicker

Usage:

const emojiPickerRef = useRef(null);

// ...

<EmojiPicker ref={emojiPickerRef} />
Siddharth-Dagar-25 commented 9 months ago

import React, { useEffect, useImperativeHandle, useRef } from 'react';
import { Picker } from 'emoji-mart';

const EmojiPicker = React.forwardRef((props, ref) => {
  const pickerRef = useRef(null);

  useEffect(() => {
    // Initialize the Picker instance
    pickerRef.current = new Picker({ ...props });

    // Cleanup
    return () => {
      pickerRef.current = null;
    };
  }, []); // Empty dependency array to run only on mount and unmount

useImperativeHandle(ref, () => ({
    update: (newProps) => {
      // Check if the pickerRef.current is available and then update
      if (pickerRef.current) {
        pickerRef.current.update(newProps);
      }
    },
    // Add more methods or properties as needed
  }));

  return <div ref={pickerRef} />; // Use pickerRef for the div
});

export default EmojiPicker;
  1. The ref you passed to EmojiPicker is being used to expose methods to the parent component. The pickerRef is used for the div to maintain the reference to the actual DOM element.

  2. I've left the dependency array empty to ensure that the useEffect hook runs only once when the component mounts and when it unmounts. If you want the effect to run when certain props change, you should include those props in the dependency array.

  3. In the update method exposed through useImperativeHandle, there's a check to ensure pickerRef.current is not null before calling update on it.