-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
avoid throwing in react hooks if the optimizely client is not available from the context #135
Conversation
…le from the context this allows an application to catch a thrown error from `createInstance` and use `null` as a fallback for the OptimizelyProvider, keeping the application working instead of crashing. see optimizely#134 for more info fixes optimizely#134
@@ -331,22 +325,35 @@ export const useFeature: UseFeature = (featureKey, options = {}, overrides = {}) | |||
*/ | |||
export const useDecision: UseDecision = (flagKey, options = {}, overrides = {}) => { | |||
const { optimizely, isServerSide, timeout } = useContext(OptimizelyContext); | |||
if (!optimizely) { | |||
throw new Error('optimizely prop must be supplied via a parent <OptimizelyProvider>'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
without this PR, using optimizely hooks without an <OptimizelyProvider>
would throw
Thanks for contributing. The way you are trying to fix it is by assuming that |
@zashraf1985 sounds fine, that would be the 2. solution idea from #134 |
@zashraf1985 there is one downside to your approach for fixing the issue: testability. If the hooks would work without OptimizelyProvider, components that contain the hooks could be more easily unit tested. In my current unit tests I use a mocked ReactSDKClient with an OptimizelyProvider, but it‘s annoying to maintain because I need to implement all the functions from the interface, and it changes with updates of the lib (e.g. |
I'm with @fabb, I think we should make the SDK less brittle. Possibly hooks shouldn't throw an error and fall over I think they should return an error as described here: I also think that the provider should just be a context provider with it's own its own useOptimiselyContext hook for getting and setting context. If setting the client and user id were separated either with their own functions or even when initialising context somehow, the provider should be able to exist without client being populated so if something goes wrong we can set it later. This will also prevent any rehydration issues with SSR and browser renders, if client fails or user id isn't ready. import React, {
FC,
useState,
createContext,
useContext,
Dispatch,
SetStateAction,
} from "react";
import { ReactSDKClient } from "@optimizely/react-sdk";
export type OptimizelyContextStateType = {
optimizely: ReactSDKClient | null;
isServerSide: boolean;
timeout: number | undefined;
};
const defaultState: OptimizelyContextStateType = {
optimizely: null,
isServerSide: false,
timeout: 0,
};
export type OptimizelyContextProviderType = [
OptimizelyContextStateType,
Dispatch<SetStateAction<OptimizelyContextStateType>>
];
export const OptimizelyContext = createContext<OptimizelyContextProviderType>([
{ ...defaultState },
() => {},
]);
export const useOptimizelyContext = () => useContext(OptimizelyContext);
export const OptimizelyContextProvider: FC = ({ children }) => {
const [state, setState] = useState({
...defaultState,
});
return (
<OptimizelyContext.Provider value={[state, setState]}>
{children}
</OptimizelyContext.Provider>
);
}; you would then know it's totally safe to wrap your app in the provider because it just stores variables any other file could do this sort of thing: import { useOptimizelyContext } from "@optimizely/react-sdk";
const [optimizelyContext, setOptimizelyContext] = useOptimizelyContext();
const { optimizely } = optimizelyContext;
if (optimizely) {
const user: UserType = {blah blah}
optimizely.setUser(user)
}
// or when initialising
try {
const client = await setUpClient();
setOptimizelyContext({ ...optimizelyContext, optimisely: client })
} catch (err) {
} |
@Develliot - thanks for the suggestion! Will follow up on #152 regarding the useDecision hook fall over. As for the provider change, though the change you suggested makes sense, we'd probably have to change the way we currently initialize the React SDK which may result in breaking changes for other users. We'll continue discussing internally, but in the meantime I'd recommend posting the suggestion to our feature request board here and we'll prioritize it based on the number of votes it gets. Thanks, |
Cleaning up old PR's - Seeing this has an ending comment, and merges tied to linked PR's- This can be closed. |
this allows an application to catch a thrown error from
createInstance
and usenull
as a fallback for the OptimizelyProvider, keeping the application working instead of crashing.see #134 for more info
fixes #134