Updating user data with user.set() doesn't work across tabs and across browsers (only after logout/login)

Hey Moralis community :slight_smile:

Just wanted to ask a question about your experiences in running Moralis powered web applications.
I’m working on an React / Next.js app and the user should be able to toggle between light and dark theme in frontend.
For saving a custom setting in Moralis (I want it stored in the users’ profile) I currently do it like this:

user.set("settings", { theme: "dark" })
await user.save()

and it works, a custom object settings is stored with theme: "dark" in it.

My case is now that if I use this data to set the users theme accordingly, the toggling between light and dark theme works great (also storing it accordingly in the User Object) BUT only in the current browser tab.
If I try out another browser, or a new tab in the same browser, where the same user is also logged in already, changing the value won’t affect the user data there, even after page reload.
It is a bit weird as I am not requesting the data from localStorage or so but from the Moralis database itself with user.attributes.settings.theme to get the value.

Expected behaviour:
After toggling the settings and after page reload in other browsers the theme should be changed and console.log(user.attributes.settings.theme) should return the updated value from the Moralis User Object.

what happens:
theme does not change on page reload in other browsers and also console.log(user.attributes.settings.theme) still consoles the same value, even though the value was changed in the database with user.set() and saved with user.save() in another tab / browser.
BUT IT WORKS great after logout and login by the way! The value shows correctly after logout / login in other browsers.

Now I’m trying to figure out if this happens because of my react/app configuration or if there is some caching built into Moralis, or maybe someone else has the same issue … how to solve this problem?

Hopefully it is clear what I want to achieve.
Thanks and best regards! Tim

1 Like

Hey @dataluchs

I’ve tested and the exmaple below works correctly:

import { useMoralis } from "react-moralis";

function App() {
  const { user } = useMoralis();

  const showData = () => {
    console.log(user.attributes.theme);
  };
  const changeData = async () => {
    console.log(user.attributes.theme);
    user.set("theme", "black");
    await user.save();
    console.log(user.attributes.theme);
  };
  return (
    <div>
      <button onClick={() => changeData()}>changeData</button>
      <button onClick={() => showData()}>showData</button>
    </div>
  );
}

export default App;

After changeData() if I call showData() it returns me correct attributes.

If you will share your code I’ll be able to take a look at it and solve your problem :man_mechanic:

1 Like

hey @Yomoo thanks a lot for replying :slight_smile: I created a simple JSON.stringify example + I added some state to update the component
If you update the theme property and then switch to another browser where you are logged in as well and hit reload the user.attributes.theme seem not to be updated accordingly (in the same browser / multiple tabs across chrome f.e. it works). Would be happy if you can reproduce it, but maybe i am simply overlooking the error

import { useMoralis } from "react-moralis";
import { useState } from 'react'

function App() {
  const [theme, setTheme] = useState("light")
  const { user } = useMoralis();

  const setLightTheme = async () => {
    user.set("theme", "light");
    await user.save();
    setTheme(user.attributes.theme)
  }

  const setDarkTheme = async () => {
    user.set("theme", "dark");
    await user.save();
    setTheme(user.attributes.theme)
  }

  return (
    <div>
      <button onClick={() => setDarkTheme()}>set dark theme</button>
      <button onClick={() => setLightTheme()}>set light theme</button>

      <pre>
        {JSON.stringify(user?.attributes, undefined, 4)} 
      </pre>

    </div>
  );
}

export default App;

I think you just need to work this your states. Because changing data on moralis tdatabase work correctly.

Every time you click setDarkTheme or setLightTheme value in Moralis Database updates immediately.

Try that exmaple:

import { useMoralis } from "react-moralis";
import { useEffect, useState } from "react";

function App() {
  const { user } = useMoralis();
  const [userAttributes, setUserAttributes] = useState();
  useEffect(() => {
    user?.attributes
      ? setUserAttributes(user.attributes)
      : setUserAttributes(null);
  }, [user]);

  const setLightTheme = async () => {
    user.set("theme", "light");
    await user.save();
    setUserAttributes(user.attributes);
  };

  const setDarkTheme = async () => {
    user.set("theme", "dark");
    await user.save();
    setUserAttributes(user.attributes);
  };

  return (
    <div>
      <button onClick={() => setDarkTheme()}>set dark theme</button>
      <button onClick={() => setLightTheme()}>set light theme</button>

      <pre>{JSON.stringify(userAttributes, undefined, 4)}</pre>
    </div>
  );
}

export default App;

All data will be updated immidiatly on the screen

1 Like

hey thanks!
yes the database is updated indeed, if I check the admin moralis dashboard / database the respected values are updated instantly (all the saving to the db works fine).
The problem seems to be with my react frontend or maybe how react-moralis fetches the userdata.
I tried with a fresh create-react-app and next-app, but your code still does not solve my issues - the updated data from the database is not correctly fetched on reload in other browsers.
I also tried another way and updated the database manually via the admin portal, and then fetched again in my frontend, the user data is not fetched with the updated value from the db (even though the code shoud do exactly that, get all the current user data from db)

// this should return the current user data from the database with all attributes 
// stored at the time of data fetching but it actually still returns previous values
const { user } = useMoralis();
  const [userAttributes, setUserAttributes] = useState();
  useEffect(() => {
    user?.attributes
      ? setUserAttributes(user.attributes)
      : setUserAttributes(null);
  }, [user]);

Thanks a lot for your help, but I will skip this for now as I can’t make sense out of it, maybe someone will have the same issue in the future

1 Like

Hey @dataluchs

Our developer @mayjer gave a detailed answer:

The theme value is not automatically updated in the client unless you explicitly query for it again. If keeping everything synced is important you need to use a Live Query so each client is notified when the theme value is changed by another client.

Take a look at Live Queries in the Moralis docs.

For the React: https://github.com/MoralisWeb3/react-moralis#usemoralissubscription

Hope this helps :man_mechanic:

1 Like

thanks @Yomoo for your support, will take a look how to implement this with live queries!

You are welcome @dataluchs

The dev team is currently considering about updating the user object’s logic so that it automatically downloads data from the server when the page is refreshed.

Also you can create a useEffect hook for setting user manually with:

const { Moralis } = useMoralis();
const [user, setUser] = useState();

useEffect(()=> {
  Moralis.User.current().fetch().then((user) => setUser(user))
}, [])

I haven’t tested it, but i think this is a good hint to you :grinning:

Happy BUIDLing :mage: :man_mechanic:

2 Likes

@Yomoo that sound great, at least that would be the logic I would personally prefer to handle updated user data when a page is refreshed :wink:
Will try to model my way around with useEffect and will add more code examples here at times :slight_smile:

Ad: I created another thread in the JS section regarding updating a list with objects from react hooks, this may be related, fyi.