MoralisWeb3 / react-moralis

Hooks and components to use Moralis in a React app
MIT License
624 stars 166 forks source link

Hook causes a React state update on an unmounted component #209

Open Kipitup opened 2 years ago

Kipitup commented 2 years ago

New Bug Report

Checklist

Issue Description

Hello,

I have a simple create-react-app that use React Router. As soon as I use a react-moralis hook, I have a "React state update on an unmounted component" error. (see full error below) This error happens only on the first loading and with hard refresh.

Here is my simple component with a react-moralis hook:

import { useMoralis, useEnsAddress } from "react-moralis";

export default function HomePage() {
  const { account } = useMoralis();
  // This hook trigger the error
  const { name } = useEnsAddress(account);

  return(
    <div>
      {account && 
        <>
          <p>Address: {account}</p>
          <p>ENS: {name}</p>
        </>
      }
    </div>
  )
}

And here is my App.js

import { useEffect } from "react";
import { useMoralis } from "react-moralis";
import { Outlet, Routes, Route, NavLink } from 'react-router-dom';
import Account from "components/Account/Account";
import HomePage from "components/HomePage";
import SearchProfile from "components/SearchProfile";

function App() {

  const { isWeb3Enabled, enableWeb3, isAuthenticated, isWeb3EnableLoading } = useMoralis();

  useEffect(() => {
    const connectorId = window.localStorage.getItem("connectorId");
    if (isAuthenticated && !isWeb3Enabled && !isWeb3EnableLoading) {
      enableWeb3({ provider: connectorId });
    }
  }, [isAuthenticated, isWeb3Enabled]);

  function Layout() {
    return(
      <div>
        <div className="flex justify-center items-center space-x-10 p-3">
          <NavLink to="/" className="text-white text-xl font-bold">
            Home
          </NavLink>
          <NavLink to="/search" className="text-white text-xl font-bold">
            Search 
          </NavLink>
          <Account />
        </div>
          <Outlet />
      </div>
    )
  }

  return (
    <Routes>
      <Route element={<Layout />}>
        <Route 
            path="/"
            element={<HomePage />}
        />
        <Route 
          path="/search"
          element={<SearchProfile />}
        /> 
      </Route> 
    </Routes>
  );
}

export default App.js

I do not have this error if I remove the React router and directly call my HomePage component. But as this React router is basic and stateless, I don't think that's where the problem come from. I have check react-moralis source code and saw that you never use clean-up function in your useEffect, maybe this is the issue?

Environment

Client

Logs

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    at HomePage (http://localhost:3000/static/js/bundle.js:2031:64)
    at Outlet (http://localhost:3000/static/js/bundle.js:124885:26)
    at div
    at Layout
Kipitup commented 2 years ago

@ErnoW possible to have your opinion on this please ?

Kipitup commented 2 years ago

@ErnoW I still have the problem, please

ErnoW commented 2 years ago

Possibly what's happening is that an async request is made and not finished when the app is loaded. Did you wrap the router provider provider around the MoralisProvider, or the other way around? That might maybe also help 🤔 . Best is to have the MoralisProvider wrap the router provider.

<MoralisProvider>
   <RouterProvider> 
      <App />
   </RouterProvider>
</MoralisProvider>

Will look into it if we can cleanup async requests, not sure if it is always possible, and in most cases we don't even need it.

It should not impose any real issue in the app, but we will see if we can resolve this warning.

Kipitup commented 2 years ago

Thanks for your answer.

I was wrapping the router provider around the Moralis one. Changed it the other way around but still have the error.

Here is my index.js for more detail:

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import "@/index.css";
import App from "@/App.jsx";
import { MoralisProvider } from "react-moralis";

/* ------------------------------- 
Setup Moralis server 
---------------------------------*/
const APP_ID = import.meta.env.VITE_REACT_APP_MORALIS_APPLICATION_ID;
const SERVER_URL = import.meta.env.VITE_REACT_APP_MORALIS_SERVER_URL;

const Application = () => {
  if (!APP_ID || !SERVER_URL) {
    throw new Error(
      "Missing Moralis Application ID or Server URL. Make sure to set your .env file."
    );
  }

  return (
    <MoralisProvider appId={APP_ID} serverUrl={SERVER_URL}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </MoralisProvider>
  );
};

ReactDOM.render(
  <React.StrictMode>
    <Application />
  </React.StrictMode>,
  document.getElementById("root")
)

Indeed, no real issue, but I must admit it's annoying to see this error every time I reload my page.