trufflesuite / drizzle

Reactive Ethereum dapp UI suite
906 stars 238 forks source link

Drizzle store is not unsubscribed on component unmount #61

Open 0xTimepunk opened 4 years ago

0xTimepunk commented 4 years ago

Hello,

I am developing a dApp that has two layouts, a login and the app layout (Main). The idea is that the user lands on the login screen and can browse some information without needing to login on the dApp. Since there isn't a method to trigger the metamask pop-up and for the UX to be non intrusive, I had to put the DrizzleContext component deeper in the render tree, as parent of the Main component. When the user clicks the login button, the 'authorized' prop is set to true in redux, DrizzleLoader (which contains DrizzleContext.Provider and DrizzleContext.Consumer) is rendered, as well as the main layout, as you can see below.

My main dApp looks like the following (with react-router):

{authorized ? (
} /> } /> {routes.map(route => ( ))}
) : ( import('pages/user/login'))} /> } /> )}

And the DrizzleLoader component (which then renders the dApp 'StateHooks' which initiate some fetching from the contracts)

function DrizzleLoader(props) {

 const { children } = props
 const drizzleInstance = new Drizzle(drizzleOptions, drizzleStore)
 return (
   <DrizzleContext.Provider drizzle={drizzleInstance}>
     <DrizzleContext.Consumer>
         {drizzleContext => {
          const { drizzle, drizzleState, initialized } = drizzleContext
           if (!initialized) {
              return "Loading..."
            }
           return (
             <StateHooks drizzle={drizzle} drizzleState={drizzleState}>
                {children}
             </StateHooks>
            )
          }}
    </DrizzleContext.Consumer>
  </DrizzleContext.Provider>
 )

}

The problem I am having is on user logout. When the user wishes to logout, the redux state is cleaned, putting the 'authorized' flag to false. This should switch to the Login layout and unmount DrizzleContext (inside DrizzleLoader), effectively ending the subscription to the drizzle store.

The problem is, I can see in Redux Dev Tools that the block updates keep coming and on the next login tentative it is as if DrizzleContext was not unmounted and drizzle is not properly re-injected in the dApp, giving me errors of like 'Cannot read property 'accounts' of undefined' in drizzle.web3.eth.accounts, as soon as the switch to the Main layout happens again. It is as if drizzle does not have enough time to properly cache information (it is asynchronous, I know, but why is it working on the first login tentative?)

My current workout is to trigger a window.location.reload() on user logout, completely refreshing everything which seems to kill the subscription, but this is not optimal.

I am wondering if I am missing something here or if I am doing a bad procedure with this architectural logic.

Any support will be appreciated.

Thanks and apologies for the long text and lack for a better title

cds-amal commented 4 years ago

Hello @j-mars, can you share a repo of this so we can investigate? Thank in advance!

0xTimepunk commented 4 years ago

Hello @cds-amal

Thanks for reaching out. Unfortunately the repo I am working on is private and it cannot be shared for the time being. However I can give some detail on the structure of my dApp and some more code so maybe it could be reproduced on your side? In the meantime, if that is not sufficient to reproduce I can work to create a side repo with minimal stuff that allows the debug of this issue.

adrianmcli commented 4 years ago

I can work to create a side repo with minimal stuff that allows the debug of this issue

This would be most appreciated!

kombos commented 3 years ago

any solution on this please?

bitfede commented 3 years ago

Also actively working on a login/logout for Drizzle, it's tricky and I have no idea why nobody has thought about this before..