Closed youminkim closed 2 years ago
@youminkim - you're right this could be due to the async initialization. We will debug this; @jkw-statsig understands your requirements, so we'll respond with a solution that fits your needs in the morning.
On the provider:
<StatsigProvider
sdkKey={process.env.NEXT_PUBLIC_STATSIG_CLIENT}
user={{
userID,
}}
>
You should specify the waitForInitialization=true
property if you want to only render the remainder of the app after Statsig has initialized. The other option is to not wait for initialization at the root, and instead use fetchGate
to await asynchronously at the callsite.
waitForInitialization=true
means blocking the website rendering?
fetchGate
may I know how to use?
I am not sure if this is possible but I prefer the way to update userID
. For example, a customer who initially did not login can login in the website and we need to update userID
@youminkim is there a way for you to generate a unique id on server side and set it as a cookie so subsequent requests from the client would carry that same id?
@youminkim if you do not want to wait for initialization in StatsigProvider
, you can set the value to be false there so that it does not block rendering, and replace your current useGate
call with fetchGate
, because fetchGate
is async, you should call it within useEffect like this:
const [showAdsense, setShowAdsense] = useState(true)
useEffect(()=>{
fetchGate('adsense2').then((gate) => setShowAdsense(gate.value))
})
Regarding your question about updating userID, I think there are 3 scenarios and here are my thoughts:
user A (new user) visits your site while logged out, and then registers during the session - ideally you use the same user ID you generated for them before & after registration.
user A (returning user) visits your site while logged out, then logs in, and the IDs are different - you can call updateUser
to switch the user and we will log future events under the new ID. However, currently there isn't a way to associate events from the previous ID with the new ID. We have plans in place to introduce an API to do that so you can associate events from two different IDs together.
user A visits your site, then switches to user B. In this case you can just use updateUser
mentioned above.
Is #2 the scenario you are talking about here? We'll provide an update once we have that feature implemented.
Hope this helps! Let us know if you have any more questions.
We have discovered an issue with the SDK when you do not pass waitForInitialization=true
and we are working on a fix
Published SDK version v0.3.0 this afternoon. This removes the fetchGate/fetchConfig/fetchExperiment parameters. I am updating the documentation now, but my suggestion is:
If you dont want to use waitForInitialization=true to render your entire app once the sdk is initialized, you can instead leave that off and still add useGate('gate_name')
in the component where you want to check a gate value.
That will initialially give you false
, until the SDK initialization completes, and then will trigger a re-render of the component because the value has changed.
Hope this helps! I'll keep this issue open until you can verify this is working for your use case
My suggestion, based on your initial code:
Leave the provider untouched.
Then, in your Shop component
export default function Shop(props) {
...
const statsig = useStatsig();
useEffect(()=>{
statsig.logEvent("page_view", shop_name)
})
...
const showAddSenseGate = useGate('adsense2');
then in your component:
{showAdSenseGate.value ? <Ad /> : null }
This is in line with what @jkw-statsig suggested as well - leave the default for the gate off, and once the value is set to true, the ad will be rendered
Thanks all for helping this.
@tore-statsig
I updated the react sdk but still same result. In the original code, I am not sure my updated userID
state is applied or not. Is there way to check current userID?
Should I call explicitly call statsig.updateUser
function to update userID?
Are you still always getting false with const showAddSenseGate = useGate('adsense2');
?
You shouldn't need to manually call updateUser
yourself, unless some time in the session a new user logs in.
Would be great if there is a way for us to see more of your code to help with debugging, e.g. if your code is on GitHub we can take a look. In the meantime one thing you can try is hardcoding the userID
in StatsigProvider
call with a bunch of different values, e.g. 1 - 20, and if you get true
sometimes. If so, then it's probably related to how you are setting the userID, but if you are still only getting false, it's likely related to other part of the code.
Hi, yes still getting false.
I just created a test code but same https://codesandbox.io/s/lively-wind-759uw?file=/pages/_app.js
Thanks for sharing @youminkim! That was helpful and I was able to find out the issues you have in your code. Here is my fork that fixed those issues and it's working so you can give it a try first https://codesandbox.io/s/recursing-wright-yy91s?file=/pages/_app.js . Here are some tips/recommendations:
useEffect
. You were right earlier about needing to use updateUser
when you want to change userID after the initialization, but I recommend using the correct userID for the initial rendering.Because window.localStorage
is not always immediately available during your initial rendering (it won't take long though), I suggest that you wait for it to become available, get userID from it, then return StatsigProvider
(do something similar to my code above). This should not delay your initial rendering by much at all.
Math.random
generates a "pseudo random" number that uses your computer's time, so when you test locally by refreshing at a fast speed, you can get many consecutive "false" in a row, so you might have to try 10+ times to get a true if you are unlucky (I did and thought something was wrong :) ). I would recommend using something like uuid
to generate IDs for users in the future.
When you are testing the new changes, because you are caching the userID, you will get the same result every time if you use your localStorage, which is the intended behavior. Make sure to disable that if you want to test the "randomness" locally, which I did to record the demo video attached below.
Hope this helps!
Thank you @jkw-statsig for detailed explanation.
needing to use updateUser when you want to change userID after the initialization
Can we explore this more? I tried with useStatsig
but seems not working https://codesandbox.io/s/crimson-rgb-6vzrw?file=/pages/_app.js
In your example, I need to wait until useEffect
execution meaning I cannot use pre-rendering anymore. In same reason, I could not use waitForInitialization=true
. Attaching NextJS pre-rendering details https://nextjs.org/learn/basics/data-fetching/pre-rendering
Hmm I'm not very sure about the requirement for pre-rendering, but if your goal is to only render a static page on the first rendering and update to use user-specific values (gates) later, there is actually no reason to use StatsigProvider
in the very initial rendering. You can make a small adjustment to the code I shared earlier and make it work the way you want:
if (userID != null) {
return (
<StatsigProvider
sdkKey={...}
user={{
userID
}}
waitForInitialization={true} // you can actually wait for initialization here now because this is designed to be rendered after the initial rendering
>
<Component {...pageProps} />
</StatsigProvider>
);
} else {
return <Component {...pageProps} />;
}
Hope this works for you!
Meanwhile we'll look into the issue with updateUser
separately, and potentially make changes to allow the user be updated by simply calling StatsigProvider
again with a different userID.
Without StatsigProvider
provider, I am not sure how my child component's useGate
hook works. I may need to manually check if the context exists which is not ideal.
I believe the best way is that StatsigProvider
accepts user changes. Otherwise, in my context, calling functions directly from JS SDK would be more straightforward.
@youminkim in the case where StatsigProvider
isn't called yet, calling useGate
will simply return false, which is actually better than providing a placeholder userID first only to switch it soon after. I think there are 3 good solutions for you:
1. If you need/prefer to provide your own userID, so that you can use it for other purposes:
You can do what I suggested above and return your child component first without StatsigProvider
until you retrieve the userID from localStorage
. useGate
will simply return false until StatsigProvider
is initialized later, no context needed from you. Give it a try :).
if (userID != null) {
return (
<StatsigProvider
sdkKey={...}
user={{
userID
}}
waitForInitialization={true}
>
<Component {...pageProps} />
</StatsigProvider>
);
} else {
return <Component {...pageProps} />;
}
2. If you do not need to create your own userID for any reason:
You can simply wrap StatsigProvider
around your child component during the initial rendering, and provide no userID at all. Statsig SDK creates a "stableID" that is stored in the localStorage
and will use it whenever you do not provide a userID. So if you don't need your own userID for anything else, you can simply rely on Statsig.
return (
<StatsigProvider
sdkKey={...}
>
<Component {...pageProps} />
</StatsigProvider>
);
NOTE: when you test this, your gate value on your device will be consistent across sessions, so you will always get either false or true. You need to clear your local storage to try to get a different value if you wish.
We think the first two options should work for your scenario, depending on whether you need to create your own userID or not, 2) is slightly simpler than 1). We'd be happy to chat about this via a VC call if you still have issues or questions. Feel free to ping me on Slack if that's needed!
Sorry for the late reply! Busy with other feature launch. Let me try soon the recommended path
No worries Youmin - let us know what works, we want to make sure the SDK fits your needs.
Hi @jkw-statsig I am also facing the same issue. Refer https://stackoverflow.com/questions/69113756/statsig-how-to-get-true-value-from-feature-gate. Can u help me out for this issue asap?
@rshruthir, could you post the entire file? One of our engineers will be up in a few hours to help you debug.
Meanwhile, please also feel free to join our slack channel: https://statsig.com/slack
I think this is very out of date, and is being referenced by more folks for unrelated issues. I'd recommend trying v1.0.0 of the react SDK. Feel free to open a new issue or ask in slack if there are additional problems using the SDK. @youminkim if you feel this was closed before your issue was resolved, feel free to reopen with the latest status, but first I would try the latest version of the SDK.
Thanks!
Hi, I am using NextJs and adopting feature gate with react-sdk. However, my gate value is always
fail
although my setting has 50% fail rate. I suspect this is related to my asynchronous init of StatsigProvider. Can you verify my implementation is alright?_app.js
Main.js
In this example,
showAdsense
value is alwaysfalse