Skip to content

getAuthenticatedUser no longer updates / re-renders after React Router v6 upgrade #591

Closed
@adamstankiewicz

Description

@adamstankiewicz

Description

Seemingly since this PR to upgrade @edx/frontend-platform to React Router v6, components seem to need to be explicitly subscribed to the AppContext when retrieving the authenticated user object within a component as opposed to continuing to rely on getAuthenticatedUser.

This change in behavior resulted in several critical user flows regressing/breaking on production for the frontend-app-learner-portal-enterprise MFE since this PR merged (e.g., infinite loading spinners because the MFE expects getAuthenticatedUser to always represent the full metadata about the user, and it no longer always does). The React Router v6 upgrade was since reverted in this MFE as a result.

Context

The initialize function (entry point for MFEs) allows consumers to optionally hydrateAuthenticatedUser which tells @edx/frontend-platform to make an API call (http://localhost:18000/api/user/v1/accounts/<username>)to retrieve additional metadata about the user (e.g., name, profile image, etc.).

For MFEs, there's generally 2 mechanisms to extract the user's metadata from @edx/frontend-platform, both of which are patterns used by MFEs today:

getAuthenticatedUser

The getAuthenticatedUser function (docs / source) ultimately calls the AxiosJwtAuthService.getAuthenticatedUser function which simply returns whatever this.authenticatedUser it has available.

function MyComponent() {
  const authenticatedUser = getAuthenticatedUser();
  return (
    <div>
      <p>Authenticated Username: <strong>{authenticatedUser.username}</strong></p>
      <p>
        Authenticated user&apos;s name:
        <strong>{authenticatedUser.name}</strong>
        (Only available if user account has been fetched)
      </p>
    </div>
  );
}

AppContext

The AppContext context provider includes (presumably) the same authenticatedUser object as should be returned by getAuthenticatedUser(). However, by subscribing to the AppContext, any time the authenticatedUser changes, the component is guaranteed to re-render with the latest authenticatedUser data.

function MyComponent() {
  const { authenticatedUser } = useContext(AppContext);
  return (
    <div>
      <p>Authenticated Username: <strong>{authenticatedUser.username}</strong></p>
      <p>
        Authenticated user&apos;s name:
        <strong>{authenticatedUser.name}</strong>
        (Only available if user account has been fetched)
      </p>
    </div>
  );
}

Regression

The regression noticed in frontend-app-learner-portal-enterprise and also reproducible in frontend-platform example MFE is that after the React Router v6 upgrade in @edx/frontend-platform, relying on getAuthenticatedUser is not guaranteed to have the correct metadata MFE developers might expect.

When debugging, it was observed that when relying on getAuthenticatedUser before React Router v6 upgrade, the component first renders with the minimal set of user metadata but after a re-render of the component, it then contains the full metadata as expected.

Now, after React Router v6 upgrade, there is only a single call to getAuthenticatedUser returning the minimal user metadata (i.e., missing the hydrated metadata from the API). This seems to be an unexpected change in behavior.

The known workaround is to migrate components away from getAuthenticatedUser() in favor of pulling from AppContext instead to ensure the component is properly re-rendered in order to have the fully hydrated user metadata. That said, an ideal fix would ensure getAuthenticatedUser() always returns the same metadata as returned by AppContext as most consumers would likely expect both mechanisms to have the same behavior, returning the same hydrated user metadata, when used within a component.

Actual

The behavior after React Router 6 upgrade shows a single console.log of the minimal authenticated user metadata. It is missing the full hydrated user metadata including properties like profileImage, etc. until something triggers a re-render of the component.

image

Expected

The behavior before React Router v6 upgrade shows the console.log of the minimal authenticated user metadata first, then an automatic component re-render which then forces another console.log including the full authenticated user metadata instead.

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugReport of or fix for something that isn't working as intended

    Type

    No type

    Projects

    Status

    Closed

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions