happykit / flags

⛳️ Feature Flags for Next.js
https://happykit.dev
MIT License
1.01k stars 11 forks source link

Providing user arg to useFlags causes flicker on initial page load #43

Closed richardantao closed 1 year ago

richardantao commented 1 year ago

I am getting the initialFlagState inside getServerSideProps so that useFlags.initialState is defined when the page mounts, as shown below.

import { FlagUser } from "@happykit/flags/dist/client";
import { FlagBagProvider } from "@happykit/flags/dist/context";
import { getFlags } from "flags/server";
import { InitialFlagState, useFlags, useFlagBag } from "flags/client";

interface PageProps {
  readonly initialFlagState: InitialFlagState;
  readonly: FlagUser | null;
}

const Child = () => {
  const { flags } = useFlagBag();

  return (
    <div>
      { 
        flags?.NOTE_UPLOAD && (
          <button>Upload</button>
        )      
      }
    </div>
  );
}

const Page: NextPage<PageProps> = ({ initialFlagState, user }) => {
  return (
    <FlagBagProvider value={useFlags({ initialState: initialFlagState, user })}>
      <Child />
    </FlagBagProvider>
  );
}

export const getServerSideProps: GetServerSideProps = async context => {
  const { initialFlagState } = await getFlags({ context });

  const user = await loginSilently(context);

  return { props: { initialFlagState, user } };
};

When I only provide { initialState: initialFlagState } to useFlags, there is no issue on the initial render, but when I provide { initialState: initialFlagState, user } to useFlags, the boolean flag flags?.NOTE_UPLOAD changes state, causing the button wrapped in the flag to flicker. user should not change when the page mounts because it is fetched via SSR, but for some reason it looks like it causes useFlags to rerender, thereby causing the flicker.

Any suggestions?

dferber90 commented 1 year ago

In const { initialFlagState } = await getFlags({ context }); you are not passing the user, so the flags in initialFlagState are not evaluated for a user. When the initialFlagState then makes it to the client, useFlags detects that it is being passed a user but that the initialFlagState was not evaluated for a user. It then refetches which causes the flicker.

To fix it, you need to pass the user to getFlags({ context, user })

dferber90 commented 1 year ago

I also noticed you are importing from @happykit/flags/dist/client and @happykit/flags/dist/context. You should be able to remove the /dist

richardantao commented 1 year ago

When the initialFlagState then makes it to the client, useFlags detects that it is being passed a user but that the initialFlagState was not evaluated for a user. It then refetches which causes the flicker.

Makes sense! Will close this issue.

I also noticed you are importing from @happykit/flags/dist/client and @happykit/flags/dist/context. You should be able to remove the /dist

Thanks. That's the path Intellisense provided.