Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

different behavior with componentDidMount than useEffect when using jquery emoji plugin

I’m stuck using a jquery emoji plugin on one of my components until I finish with a custom plugin I’m building.

For some reason, when I call the emoji plugin inside of componentDidMount, everything works except the ability to utilize a custom button to show the emoji modal. When I use a custom button, the emoji plugin doesn’t attach the event to the button.

What’s crazy is that I can use the same exact code in useEffect, and it attaches the event listener to the custom button just fine.

I verified that the event listener is not attached by looking in the web console at events attached to the element after the page loaded.

You can easily reproduce this problem by placing this component somewhere in an app (and importing jquery with the emoji-area plugin):

import React, {useEffect} from 'react';

  export default function CommentInput(props) {

    useEffect(() => {
      const id = props.blurtId,
            $wysiwyg = $('#' + id).emojiarea({
            button: '#emoji-btn' + id
          });


      $.emojiarea.path = '/js/jquery/emojis/';
      $.emojiarea.icons = {
        ':smile:'     : 'smile.png',
        ':angry:'     : 'angry.png',
        ':flushed:'   : 'flushed.png',
        ':neckbeard:' : 'neckbeard.png',
        ':laughing:'  : 'laughing.png'
      };

   }, []); 

   return (
     <>
        <textarea id={props.blurtId} className='blurt-comment-input' />
        <i id={'emoji-btn' + props.blurtId} className='fa fa-smile emoji-btn' />  
     </>
   )

}

Simply change this to a class component, and you’ll see that within componentDidMount, everything works except the custom button. Any idea what could cause this change in behavior??

Here is the react class component version:

import React, {Component} from 'react';

class CommentInput extends Component {

constructor(props) {
    super(props);
}

componentDidMount() {
    const id = this.props.blurtId,
          $wysiwyg = $('#' + id).emojiarea({
            button: '#emoji-btn' + id
        });


    $.emojiarea.path = '/js/jquery/emojis/';
    $.emojiarea.icons = {
        ':smile:'     : 'smile.png',
        ':angry:'     : 'angry.png',
        ':flushed:'   : 'flushed.png',
        ':neckbeard:' : 'neckbeard.png',
        ':laughing:'  : 'laughing.png'
    };
}; 

render() {
    return (
        <>
            <textarea id={this.props.blurtId} className='blurt-comment-input' />
            <i id={'emoji-btn' + this.props.blurtId} className='fa fa-smile emoji-btn' />  
        </>
      )
    }
}

export default CommentInput;
like image 765
silencedogood Avatar asked Aug 28 '19 17:08

silencedogood


People also ask

What are the differences between useEffect and componentDidMount?

From the previous question, we found out that componentDidMount doesn't have the same behavior with useEffect hook, because componentDidMount invoked synchronously before the browser paints the screen, while useEffect is invoked asynchronously after the browser has already painted the screen.

What is componentDidMount in useEffect?

componentDidMount fires and sets state immediately (not in an async callback) The state change means render() is called again and returns new JSX which replaces the previous render.

Can we use componentDidMount in functional component?

Using componentDidMount in functional components with useEffect. This is how we can perform the equivalent of componentDidMount in functional components using the useEffect Hook: useEffect(() => { // Inside this callback function we perform our side effects. });

What is componentDidMount and componentDidUpdate?

componentDidMount() : invoked immediately after a component is mounted (inserted into the DOM tree) componentDidUpdate(prevProps, prevState, snapshot) : is invoked immediately after updating occurs. This method is not called for the initial render.


2 Answers

There is a difference between when componentDidMount and useEffect fires.

From the useEffect docs :

Unlike componentDidMount and componentDidUpdate, the function passed to useEffect fires after layout and paint

like image 173
Mohamed Ramrami Avatar answered Oct 23 '22 06:10

Mohamed Ramrami


The big difference between componentDidMount and useEffect is that useEffect is run after every render, not just the first one. Since your render outputs a new element on each render, after the first render the DOM element you attached the emoji thing to doesn't exist anymore, and a new one with the same ID does.

Options:

  • Use componentDidUpdate to handle the subsequent renders. (You'll still need componentDidMount for the first one.)
  • Use a callback ref.
like image 4
T.J. Crowder Avatar answered Oct 23 '22 06:10

T.J. Crowder