12

I use the react-tooltip library in my Next.js app.

I noticed that every time I refresh a website while visiting a page that uses the tooltip I get an error:

react-dom.development.js:88 Warning: Prop `dangerouslySetInnerHTML` did not match.

CSS classes are different on the client and on the server

The weird part is I do not get that error while navigating from a random page to a page that uses the react-tooltip.

The tooltip related code:

<StyledPopularityTooltipIcon src="/icons/tooltip.svg" alt="question mark" data-tip="hello world" />
<ReactTooltip
    effect="solid"
    className="tooltip"
    backgroundColor="#F0F0F0"
    arrowColor="#F0F0F0"
    clickable={true}
/>
Damian Kociszewski
  • 283
  • 1
  • 5
  • 20

4 Answers4

11

I had the same issue, I had to use state to detect when component has been mounted, and show the tooltip only after that.

P.S. You don't see the error when navigating, because the page is not rendered on server when you navigate, it's all front-end :)

lemurry
  • 251
  • 2
  • 7
  • @lemurry could you provide the sample code? How did you go about detecting, if the component was mounted? – Fabian Bosler Dec 14 '20 at 10:24
  • 4
    @FabianBosler you can do it using useState and useEffect which is executed only on first render. https://codesandbox.io/s/brave-rosalind-4bb4v?file=/src/App.js Let me know if you need further explanation. – lemurry Jan 02 '21 at 10:05
11

In case you are using any server-side rendering (like Next.js) - you will need to make sure your component is mounted first before showing the react-tooltip.

I fixed this by using the following:

import React, { useEffect, useState } from 'react';

const [isMounted,setIsMounted] = useState(false); // Need this for the react-tooltip

useEffect(() => {
    setIsMounted(true);
},[]);
 
return (<div>
      {isMounted && <ReactTooltip id={"mytip"} effect={"solid"} />}

      <span data-tip={"Tip Here"} data-for={"mytip"}>Hover me</span>
</div>)
Niv Apo
  • 983
  • 1
  • 9
  • 18
5

You should wrap your JSX in the following component:

import React, { useEffect, useState } from 'react';

const NoSsr = ({ children }): JSX.Element => {
  const [isMounted, setMount] = useState(false);

  useEffect(() => {
    setMount(true);
  }, []);

  return <>{isMounted ? children : null}</>;
};

export default NoSsr;

Like this:

<NoSsr>
 <YourJSX />
</NoSsr>
AmerllicA
  • 29,059
  • 15
  • 130
  • 154
  • this is the cleaner solution with a reusable component, this should be the accepted answer. – sagat Oct 15 '21 at 20:58
4

If you are working with NEXTJS this might be a good approach, you can check the documentation here as well, also if you are working with data-event, globalEventOff or any other prop and is not hiding or not working in your localhost, this only occurs in Development Strict Mode. ReactTooltip works fine in Production code with React 18. So you can set reactStrictMode : false, in your next.config.js to test it locally and then set it back to true, hope this helps :) info reference here

import dynamic from 'next/dynamic'

const ReactTooltip = dynamic(() => import('react-tooltip'), { ssr : false });

function Home() {
  return (
    <div>
     <Button
      data-tip
      data-event="click focus"
      data-for="toolTip"
      onClick={():void => ()}
     />
     <ReactTooltip id="toolTip" globalEventOff="click"/>
    </div>
  )
}

export default Home