GithubHelp home page GithubHelp logo

optimizely / react-sdk Goto Github PK

View Code? Open in Web Editor NEW
88.0 61.0 35.0 1.14 MB

React SDK for Optimizely Feature Experimentation and Optimizely Full Stack (legacy)

Home Page: https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/javascript-react-sdk

License: Apache License 2.0

JavaScript 2.84% TypeScript 97.16%
optimizely-environment-prod optimizely-environment-public optimizely-owner-px

react-sdk's People

Contributors

benlorantfy avatar cristianparcu-epi avatar danny-driscoll avatar farhan-opti avatar fayyazarshad avatar frehner avatar jaeopt avatar juancarlostong avatar junaed-optimizely avatar mikechu-optimizely avatar mjc1283 avatar mnoman09 avatar msohailhussain avatar opti-jnguyen avatar rafinutshaw-optimizely avatar raju-opti avatar shaharyar123 avatar yavorona avatar zashraf1985 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-sdk's Issues

new console warning in 2.2.0

I'm getting a new warning in 2.2.0 that doesn't appear if I downgrade to 2.1.0. It's not quite clear what the issue is based on the warning so I'm not sure how to fix it:

[OPTIMIZELY] - WARN 2020-08-05T16:28:18.546Z BUCKETER: Bucketed into an invalid variation ID. Returning null.

My implementation looks like the following:

const optimizely = createInstance({
  sdkKey: key,
  logLevel: 3,
})

function App() {
  const user = useUser()
  return <OptimizelyProvider
      optimizely={optimizely}
      timeout={500}
      user={{ id: user ? user.email : '' }} //have to wait for the user api to resolve
  >
    // rest of app as children
  </OptimizelyProvider>
}

also, we're only using the feature toggles at the moment in our app, nothing else.

Can you guide me as to what the warning is and how to correct it? Thanks.

Does react-sdk use any DOM APIs? Is react-native supported?

Hello Optimizely!

I'm investigating options for doing experiments in my react-native app. Does this SDK use any DOM/browser APIs that might block me from using the sdk with react-native?

I verified that it works with react-native, but should I expect it will continue working that way?

Feature request: useFeature should watch for forced variations on the client

Currently the useExperiments hook adds a listener to the client to fetch decisions if a variation has been forced. Since the useFeature hook also uses decisions if an experiment is active, it makes sense that it should also fetch the decisions, but this is currently not the case.

This can be tested by setting up an experiment and using the useFeature hook. You'll notice that if you force a variation, the useFeature properties isFeatureEnabled and variables are never updated.

Feature Request: `useDecisions` hook

The current useDecision hook can only work with one feature flag and return only one OptimizelyDecision.

In situation where more than one decision is needed, a useDecisions hook can be used rather than using multiple useDecision hooks. This is especially important for cases where the flags used would change dynamically, for example a switchByFeatureFlags function, which accept multiple flags as argument.

Optimizely breaks Gatsby

When attempting a build in Gatsby optimizely throws several es export / import errors

FYI I used this as an example: https://github.com/circAssimilate/gatsby-with-optimizely-full-stack

$ gatsby build
success open and validate gatsby-configs - 0.009s
success load plugins - 0.110s
success onPreInit - 0.004s
success delete html and css files from previous builds - 0.008s
success initialize cache - 0.006s
success copy gatsby files - 0.049s
success onPreBootstrap - 0.018s
success createSchemaCustomization - 0.002s
success source and transform nodes - 0.038s
success building schema - 0.136s
success createPages - 0.305s
success createPagesStatefully - 0.021s
success onPreExtractQueries - 0.002s
warn There are conflicting field types in your data.

If you have explicitly defined a type for those fields, you can safely ignore this warning message.
Otherwise, Gatsby will omit those fields from the GraphQL schema.

If you know all field types in advance, the best strategy is to explicitly define them with the `createTypes` action, and skip inference with
 the `@dontInfer` directive.
SitePage.context.datafile.typedAudiences.conditions:
 - type: [string,array]
   value: [ 'and', [  ] ]
success update schema - 0.094s
success extract queries from components - 0.021s
success write out requires - 0.009s
success write out redirect data - 0.002s
success onPostBootstrap - 0.001s
⠀
info bootstrap finished - 3.066 s
⠀
success Building production JavaScript and CSS bundles - 7.723s
success Rewriting compilation hashes - 0.006s
success run queries - 7.869s - 1/1 0.13/s

 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'Children' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'Component' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'Component' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'Component' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'Component' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'Component' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'cloneElement' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'createContext' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'createElement' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'createElement' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'createElement' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'createElement' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'createInstance' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'forwardRef' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'getLogger' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'getLogger' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'getLogger' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'getLogger' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'getLogger' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't import the named export 'isValidElement' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't reexport the named export 'enums' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't reexport the named export 'errorHandler' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't reexport the named export 'eventDispatcher' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't reexport the named export 'logging' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't reexport the named export 'setLogLevel' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs


 ERROR #98123  WEBPACK

Generating SSR bundle failed

Can't reexport the named export 'setLogger' from non EcmaScript module (only default export is available)

File: node_modules/@optimizely/react-sdk/dist/react-sdk.mjs

not finished Building static HTML for pages - 1.094s
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

How do I mock out provider configuration?

Is there a way to pass in an object to the provider that determines which flags are on and which are off for testing purposes? I'd like to be able to run tests where I can control different combinations of flags on an off for different tests.

TS: Property 'createUserContext' is missing in type 'OptimizelyReactSDKClient' but required in type 'ReactSDKClient' (v2.4.2)

Getting a TS error when adding OptimizelyProvider as per guide:

TypeScript error in /src/index.tsx(32,17):
Property 'createUserContext' is missing in type 'OptimizelyReactSDKClient' but required in type 'ReactSDKClient'. TS2741

    30 |             <ThemeProvider theme={theme}>
    31 |               <OptimizelyProvider
  > 32 |                 optimizely={optimizely}
       |                 ^
    33 |                 user={{
    34 |                   id: 'user123',
    35 |                 }}

React App code:

import { createInstance,  OptimizelyProvider } from '@optimizely/react-sdk';

const optimizely = createInstance({
  sdkKey: 'XXXXXXX',
});

ReactDOM.render(
  <React.StrictMode>
    <OptimizelyProvider
        optimizely={optimizely}
        user={{ id: 'user123' }}
      >
        <App />
      </OptimizelyProvider>
  </React.StrictMode>,
  document.getElementById('root'),
);

useFeature returns flag as `false` for one frame on page load, then `true`

Everything about our setup seems pretty normal. This is what our code looks like in a FC, with unrelated code stripped out.

const [foo] = useFeature('foo');
console.log(foo);

Console output:

false
true

This is resulting in us rendering a big chunk of old UI for a single frame, then the new UI.

30KB Gzipped

If I set up a client and provider, it adds 30KB (zipped) to to the main bundle that that is almost the same size as react-dom which feels a bit excessive for something that just needs to pump in client data to a useDecision hook.

Is there anyway to reduce this overhead?

CONFIG_VALIDATOR: No datafile specified. Cannot start optimizely.

Upon upgrading to 2.3.X, we get the the following error CONFIG_VALIDATOR: No datafile specified. Cannot start optimizely., however Optimizely seems to load everything after the datafile is updated from the http response for the datafile.

Screen Shot 2020-10-06 at 9 06 05 AM

Is there a way to turn off the initial error message? So far I've tried increasing the timeout in the OptimizelyProvider to no avail.

What is the difference between useFeature and useDecision hooks?

Hello 👋

I see that since 2.5 version you introduced useDecision hook and updated all docs to use it, but I am not able to find any motivation behind that. Also now there are no docs about useFeature hook, that leads to confusion over should we continue use it or not.

Can you please explain the differences of useFeature and useDecision hooks and what are the future support plans for useFeature hook since useDecision was introduced?

Thanks

Optizely instace with custom headers

I should be able to send a custom header (eg Authorization) within the request considering the fact that I can point my instance to another endpoint which may need other kinds of information

const optimizely = createInstance({
    sdkKey: 'development',
    headers: { Authorization: "23984712348213g48b8sgd8f" } // suggestion
    datafileOptions: {
      urlTemplate: 'http://localhost:3001/optimizely/datafile/%s',
    },
  })

Merge Attributes on Override Attributes and/or Pass User Attributes as Context

We have a base set of attributes that are passed to our OptimizelyProvider upon initialization. A common use case is in a hook to pass the overrideAttributes. Generally we would like to have our base attributes merged with the overrideAttributes. It looks like the OptimizelyProvider uses the .setUser method and then in the hook calls .activate with the third argument of the override attributes. I'm under the impression that this will completely override our base set of attributes.

Currently, if we pass overrides we have to access our base attributes from state or context and manually merge them in the hook. I would be nice if they were passed as context and either the hook merges them internally or we can use the Optimizely context to access the base attributes and perform the merge with overrides.

createInstance fns.assignIn is not a function

Hello,

I am trying to setup optimizely for react application. I am using react 16.9.0 and @optimizely/react-sdk 1.0.0.

I wrapped whole application with OptimizelyProvided as stated in documentation:

const optimizely = createInstance({
  sdkKey: "MY-SDK-KEY-I-CHECKED-ITS-CORRECT",
});

class App extends React.Component {
  render() {
    return (
      <OptimizelyProvider
        optimizely={optimizely}
        user={{
          id: "test-123",
          attributes: {
            "customerId": 123,
            "Location": "poland",
          },
        }}>
      ...

But during initialization I get an error in this part of your source code:

It start here:

this._client = optimizely.createInstance(configWithClientEngine);

Then inside that function I found out that fns.assignIn is not a function, it is a module.

config = fns.assignIn(
        {
          clientEngine: enums.JAVASCRIPT_CLIENT_ENGINE,
          eventBatchSize: DEFAULT_EVENT_BATCH_SIZE,
          eventFlushInterval: DEFAULT_EVENT_FLUSH_INTERVAL,
        },
        config,
        {
          eventDispatcher: eventDispatcher,
          // always get the OptimizelyLogger facade from logging
          logger: logger,
          errorHandler: logging.getErrorHandler(),
        }
      );

which leads us to situation where

this._client

is null, and in below line the onReady function on null cannot be triggered

this.dataReadyPromise = Promise.all([this.userPromise, this._client.onReady()])

May this issue be connected with webpack configuration? Could you help me with that problem?

createInstance can throw: how to graceful fallback

There are a few issues that make it impossible for the application to still work if optimizely fails to initialize:

  1. optimizely.createInstance from optimizely-sdk can return null
    https://github.com/optimizely/javascript-sdk/blob/v4.7.0/packages/optimizely-sdk/lib/index.browser.ts#L136
  2. createInstance in the react-sdk does not handle the null case and then just throws in the constructor when accessing this._client.onReady
    https://github.com/optimizely/react-sdk/blob/2.7.0/src/client.ts#L195-L201
  3. if we catch this thrown error in our application code, we cannot render OptimizelyProvider because it needs an OptimizelyReactSDKClient instance
    https://github.com/optimizely/react-sdk/blob/2.7.0/src/Provider.tsx#L27
  4. conditionally rendering the OptimizelyProvider is not an option because the optimizely hooks from react-sdk throw when there is no optimizely instance provided via the OptimizelyProvider
    https://github.com/optimizely/react-sdk/blob/2.7.0/src/hooks.ts#L332-L336
  5. the rules of hooks disallow to render hooks conditionally, so we cannot catch this issue on the application side

We currently see in production ~70.000 failed optimizely initializations / hour. All happening in Firefox, and we need to investigate more, but the main issue is that failing optimizely makes the application unusable, which is not a graceful fallback.

I have different ideas to solve this:

  1. react-sdk allows to render OptimizelyProvider with optimizely={null} and the optimizely hooks are modified to not throw anymore when no optimizely instance is available. Applications will need to catch the thrown error from the initial createInstance call and as a fallback use null. The hooks then fall back to the same values they would when optimizely is not yet ready.
  2. react-sdk does not throw in createInstance when optimizely is null and rather wraps all accesses to this._client with a null check.
  3. react-sdk provides a DummyReactClient that implements all the functions from ReactSDKClient with no functionality. Applications will need to catch the thrown error from the initial createInstance call and as a fallback use the DummyReactClient and provide it to OptimizelyProvider.

I would vote for option 1. because it still allows applications to detect when createInstance fails and allows for the maximum flexibility. Also it's backwards-compatible.

Experiment is not being evaluated sometimes - possible race condition?

Background

We are using optimizely full stack and running an experiment with 3 variations. For our frontend, we use react and hence using the optimizely react SDK.

Details of your request/issue

Expected Experience (please describe what you want):

When the user is in 'variation_3' of the experiment and visits the search results react app, they should always see the search result.

Actual Experience (please describe what you see):

When the user is in 'variation_3' of the experiment and visits the search results page, they sometimes see the search results and sometimes see a blank page.

What we suspect is the OptimizelyExperiment react component sometime does not initiate the activate and the user does not fall in the expected variation.

Is the issue in Production or a Staging/QA Environment (if in pre-production, can we access it)?

Production

Optimizely react version

@optimizely/react-sdk version 2.4.1

Browser logs

Successful experiment evaluation

[OPTIMIZELY] - INFO  2021-09-29T23:31:41.413Z DatafileManager: Updating datafile from response
[OPTIMIZELY] - INFO  2021-09-29T23:31:41.416Z PROJECT_CONFIG: Skipping JSON schema validation.
[OPTIMIZELY] - INFO  2021-09-29T23:31:41.441Z OPTIMIZELY: Updated Optimizely config to revision 1899 (project id yyyyyy)
[OPTIMIZELY] - INFO  2021-09-29T23:31:41.441Z ReactSDK: OPTIMIZELY_CONFIG_UPDATE, re-evaluating Experiment="xxxx" for user="user3"
[OPTIMIZELY] - INFO  2021-09-29T23:31:41.442Z DECISION_SERVICE: User user3 is forced in variation variation_3.
[OPTIMIZELY] - INFO  2021-09-29T23:31:41.445Z ReactSDK: Client became ready

Failure experiment evaluation

[OPTIMIZELY] - INFO  2021-09-29T23:36:51.359Z DatafileManager: Updating datafile from response
[OPTIMIZELY] - INFO  2021-09-29T23:36:51.360Z PROJECT_CONFIG: Skipping JSON schema validation.
[OPTIMIZELY] - INFO  2021-09-29T23:36:51.365Z OPTIMIZELY: Updated Optimizely config to revision 1899 (project id yyyyyy)
[OPTIMIZELY] - INFO  2021-09-29T23:36:51.369Z ReactSDK: Client became ready

In case of failure condition, we can see that the DECISION_SERVICE is not being invoked.

Any help is appreciated

Feature Request: unable to determine if a feature is turned off

Currently, when using both the useFeature hook and the OptimizelyFeature component, the only feature specific data you are returned are whether your experiment isEnabled and the variables associated with that feature. This works well when you want to toggle between two options while your feature is toggled on, but does not provide the client with any information about whether your feature is on or off. If the client receives isEnabled of false, it could mean that your feature is turned off, or it could mean that the user did not fall in the segment or group that should have the feature enabled. I'd like to propose that the hook and component return an additional value of whether the feature is toggled on or off. In our case, we would like to fallback to different functionality when the feature is off.

I'd be happy to add a PR, if this is something that your devs are willing to add.

Integrating with React Redux

My apologies if this has been addressed before - I have searched through the docs, issues & closed issues to no avail.

Do you have guidelines for integrating the optimizely SDK into redux? For our project we have done some hacky work to listen to the OptimizelyFeature status and synchronise the experiment status to the store when it gets mounted, however this feels more like a workaround than a feature.

Wondering if you have any best-practice guidelines for integrating with Redux? Many thanks.

Simple example produces console warning: Can't perform a React state update on an unmounted component

Just started integration of Optimizely's React SDK into my React project. I've used the SDK set up guide, and the product is functional: I successfully get the dev JSON datafile, it loads and checks if I have access to the feature - which I do.

However, I receive the console warning attached - pardon the length, I wanted to provide full context.

I have tried creating a timeout of 1 millisecond on the OptimizelyProvider (gives fail to initialize onReady before timeout and the same "Can't perform a React state update..." warning). I have also varied the locatino of OptimizelyProvider, starting at the highest level of the application, and brought it down several "rings" until after auth state is known (so it only triggers once when a known user is set). Additionally, I have the simplest possible set up and an OptimizelyFeature straight out of the docs.

At this point, it seems the issue is with the react-sdk, especially since the warning is most related to FeatureComponent, created by Context.Consumer.

Key versions:

  • @optimizely/react-sdk: 1.0.1
  • react: 16.11.0
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.835Z DatafileManager: Updating datafile from response
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.837Z PROJECT_CONFIG: Skipping JSON schema validation.
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.840Z OPTIMIZELY: Updated Optimizely config to revision 15 (project id 17165161924)
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.840Z <OptimizelyFeature>: feature="abc" successfully rendered for user="[email protected]"
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.842Z DECISION_SERVICE: Audiences for experiment 17283183885 collectively evaluated to TRUE.
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.843Z BUCKETER: User [email protected] is in variation 17273943456 of experiment 17283183885.
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.843Z OPTIMIZELY: Feature abc is enabled for user [email protected].
index.js:1 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
    in FeatureComponent (created by Context.Consumer)
    in WithOptimizely (created by ForwardRef(withOptimizely(FeatureComponent)))
    in ForwardRef(withOptimizely(FeatureComponent)) (at Device.tsx:313)
    in div (at Device.tsx:194)
    in div (at Page.tsx:20)
    in div (at Page.tsx:11)
    in Page (at Device.tsx:164)
    in Device (at routes.tsx:59)
    in Route (at routes.tsx:46)
    in SecureRoute (at routes.tsx:92)
>> additional detail
console.<computed> @ index.js:1
warningWithoutStack @ react-dom.development.js:530
warnAboutUpdateOnUnmountedFiberInDEV @ react-dom.development.js:25738
scheduleUpdateOnFiber @ react-dom.development.js:23679
enqueueSetState @ react-dom.development.js:13994
push../node_modules/react/cjs/react.development.js.Component.setState @ react.development.js:325
(anonymous) @ react-sdk.js:644
Promise.then (async)
FeatureComponent.componentDidMount @ react-sdk.js:635
commitLifeCycles @ react-dom.development.js:22101
commitLayoutEffects @ react-dom.development.js:25344
callCallback @ react-dom.development.js:336
invokeGuardedCallbackDev @ react-dom.development.js:385
invokeGuardedCallback @ react-dom.development.js:440
commitRootImpl @ react-dom.development.js:25082
unstable_runWithPriority @ scheduler.development.js:697
runWithPriority$2 @ react-dom.development.js:12149
commitRoot @ react-dom.development.js:24922
finishSyncRender @ react-dom.development.js:24329
performSyncWorkOnRoot @ react-dom.development.js:24307
(anonymous) @ react-dom.development.js:12199
unstable_runWithPriority @ scheduler.development.js:697
runWithPriority$2 @ react-dom.development.js:12149
flushSyncCallbackQueueImpl @ react-dom.development.js:12194
flushSyncCallbackQueue @ react-dom.development.js:12182
batchedUpdates$1 @ react-dom.development.js:24392
notify @ Subscription.js:23
notifyNestedSubs @ Subscription.js:65
handleChangeWrapper @ Subscription.js:70
dispatch @ redux.js:221
e @ VM245:1
(anonymous) @ middleware.js:22
dispatch @ VM245:1
(anonymous) @ redux.js:475
(anonymous) @ App.tsx:43
Promise.then (async)
getUser @ App.tsx:40
AppBase @ App.tsx:53
renderWithHooks @ react-dom.development.js:16260
mountIndeterminateComponent @ react-dom.development.js:18794
beginWork$1 @ react-dom.development.js:20162
beginWork$$1 @ react-dom.development.js:25756
performUnitOfWork @ react-dom.development.js:24698
workLoopSync @ react-dom.development.js:24671
performSyncWorkOnRoot @ react-dom.development.js:24270
scheduleUpdateOnFiber @ react-dom.development.js:23698
updateContainer @ react-dom.development.js:27103
(anonymous) @ react-dom.development.js:27528
unbatchedUpdates @ react-dom.development.js:24433
legacyRenderSubtreeIntoContainer @ react-dom.development.js:27527
render @ react-dom.development.js:27608
./src/index.tsx @ index.tsx:25
__webpack_require__ @ bootstrap:785
fn @ bootstrap:150
1 @ Utility.ts:126
__webpack_require__ @ bootstrap:785
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.chunk.js:1
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.845Z <OptimizelyFeature>: feature="abc" successfully rendered for user="[email protected]"
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.845Z DECISION_SERVICE: Audiences for experiment 17283183885 collectively evaluated to TRUE.
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.846Z BUCKETER: User [email protected] is in variation 17273943456 of experiment 17283183885.
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.846Z OPTIMIZELY: Feature abc is enabled for user [email protected].
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.846Z <OptimizelyFeature>: feature="abc" successfully rendered for user="[email protected]"
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.846Z DECISION_SERVICE: Audiences for experiment 17283183885 collectively evaluated to TRUE.
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.847Z BUCKETER: User [email protected] is in variation 17273943456 of experiment 17283183885.
[OPTIMIZELY] - INFO  2020-01-08T20:10:13.847Z OPTIMIZELY: Feature abc is enabled for user [email protected].

build to umd (and system?) format?

Wondering if you would be open to building to umd (and system) formats?

looking at https://github.com/optimizely/react-sdk/blob/master/scripts/build.js it seems like we could just add another line like the following

exec(`./node_modules/.bin/rollup -c scripts/config.js -f umd -o dist/${packageName}.umd.js`);

// and maybe system format?
exec(`./node_modules/.bin/rollup -c scripts/config.js -f system -o dist/${packageName}.system.js`);

shouldn't have any side effects, since the entry points will remain the same and these are just new files being built.

if you're open to it, I can make the PR as well

Issues with SSR since @optimizely/react-sdk@^2.0.0

I am trying to integrate @optimizely/react-sdk with a project that uses the next.js framework. Everything was working fine, but since the release of @optimizely/react-sdk@^2.0.0 there is a problem with the initialization of optimizely instance on the client-side.

Even though I am providing the datafile that is fetched during server-side rendering, optimizely.isReady() initially returns false.

So my experiments that are defined like below:

<p>Experiments:</p>
<OptimizelyExperiment experiment="DEV_experiment">
  {variation => <p>got variation {variation}</p>}
</OptimizelyExperiment>
<hr/>
<OptimizelyExperiment experiment="DEV_experiment">
  <OptimizelyVariation variation="variation_1">
    variation_1
  </OptimizelyVariation>
  <OptimizelyVariation variation="variation_2">
    variation_2
  </OptimizelyVariation>
  <OptimizelyVariation default>
    default
  </OptimizelyVariation>
</OptimizelyExperiment>

During the server-side render the content for variation_2.

<p>Experiments:</p><p>got variation <!-- -->variation_2</p><hr/>variation_2</div>

But in the browser, it cannot retrieve it for some reason.

<p>Experiments:</p><p>got variation </p><hr>default</div>

Instead, I can see logs in the console that Client became ready (https://github.com/optimizely/react-sdk/blob/master/src/hooks.ts#L132). However, since I provided datafile, should not the client be ready right after initialization?

To Reproduce

You can use this repository to see the issue: https://github.com/oMatej/nextjs-optimizely

I think it can be something related to: #58

Could not import @optimizely/react-sdk

After I used
yarn add @optimizely/react-sdk
And it was beed added in package.json
image

But when I import it in React like this
image
It will report warning in console.
image

And I debug in the frontend, I will stop at the point of import
image

Did I do something wrong or need some other settings?
Thanks for helping!

@Optimizely causing TS errors

My Setup/Config
Running: "@optimizely/react-sdk": "^2.7.0",
"typescript": "^4.4.4"

Tsconfig.ts
has the following in excludes: "node_modules/**/*"
has "skipLibCheck": true set in compilerOptions

Hello, when running the command below @optimizely has started to create 12 errors
tsc --noEmit --project tsconfig.json

Two sample errors:

node_modules/@optimizely/optimizely-sdk/lib/core/project_config/index.ts:167:19 - error TS2532: Object is possibly 'undefined'.

167     experiments = projectConfig.groupIdMap[Id].experiments;
                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/@optimizely/optimizely-sdk/lib/core/project_config/index.ts:222:11 - error TS2532: Object is possibly 'undefined'.

222           projectConfig.experimentFeatureMap[experimentId].push(feature.id);

Any idea why this might be happening all of a sudden? Thank you!

(Side note: seems similar to this older issue optimizely/javascript-sdk#613)

Question about user id

I'm still learning how to use optimizely, so please bear with me. How are you suppose to configure an audience based on the user {id} that is passed in. I want to configure a feature flag with a specific audience that is based of a set of user id. However, when i try to configure an audience with the attribute (id) it doesn't work. The only way i can do it is if i add the id as an attribute to the attribute object.

  <OptimizelyProvider
              optimizely={this.optimizely}
              user={{
                id: userEmail,
                attributes: { id: userEmail } 
              }}

Thanks,
Derek

setForcedVariation does not work as expected

SDK version 2.5.0
React Version 16.14.0

Description

I'm creating the client by instantiating it with the datafile, and then based upon query parameters for experiment id and variation name I'm calling client.setForcedVariation in a useMemo hook

Expected

For variation supplied in the query param to be forced

Actual

No variation is forced and user will be bucket as normal

Setup

import React, { FC, useMemo } from 'react';
import { createInstance, logOnlyEventDispatcher, OptimizelyProvider, ReactSDKClient } from '@optimizely/react-sdk';
import { eventDispatcher } from './eventDispatcher';
import { isServer } from './isServer';
import { logger } from './logger';
import { Datafile, FullstackProviderAttributes } from './types';

export const OptimizelyFullstackProvider: FC<{
  datafile: Datafile;
  attributes: FullstackProviderAttributes;
}> = ({ datafile, attributes = {}, children }) => {
  const isClient = !isServer();
  const { disableTracking, id, variation, experiment, ...restAttributes } = attributes;
  const optimizelyClient = useMemo(() => {
    const client = createInstance({
      eventDispatcher: isClient && !disableTracking ? eventDispatcher : logOnlyEventDispatcher,
      datafile,
    });

    if (variation && experiment) {
      logger.info(`forcing variation ${variation} for experiment ${experiment} and user ${id}`);
      client.setForcedVariation(experiment, variation);
    }

    return client;
  }, [datafile, disableTracking, isClient, experiment, variation, id]);

  return (
    <OptimizelyProvider isServerSide optimizely={optimizelyClient} user={{ id, attributes: restAttributes }}>
      {children}
    </OptimizelyProvider>
  );
};

Updating @optimizely/js-sdk-logging dependency

Currently the optimizely/js-sdk-logging dependency is "^0.1.0". Bc caret behavior for 0.x versions only match patch versions, it doesn't resolve to the most current ver: "^0.3.1". Are there any plans to update this dep?

I'm asking bc the optimizely/javascript-sdk repo has its @optimizely/js-sdk-logging dependency at "^0.3.1". So having optimaizely/react-sdk and optimizely/javascript-sdk in my project means I have both versions "0.1.0" and "0.3.1" of optimizely/js-sdk-logging in my bundle.

User cannot be unset

Once the user has been set, it cannot be unset anymore (e.g. for the case the user logged out or withdrew GDPR consent).

Neither user={undefined} nor user={{id: null}} work because of this code:

Screenshot 2021-10-27 at 16 47 01

Screenshot 2021-10-27 at 16 52 06

Circular structure of SDK client breaks next.js SRR

We get a SDK client on the server by running createInstance({...})

Next.js serialize all objects to json when sending them to the client.
We then get

Error: Circular structure in "getInitialProps" result of page "/_error". https://err.sh/zeit/next.js/circular-structure

The reason is that the SDKClient has a circular structure whitch is not supported in JSON

TypeError: Converting circular structure to JSON

Creating on client at the server side and the create it again in the client browser leads to a flickering behavior, since we recreate the SDK client and the turned on feature temporary goes away until we load data in the newly created client

It would be great if you could you change your SDK client to not use circular structure, so it can be serialized.

Our created SDK client looks like this

OptimizelyReactSDKClient {
  user: { id: null, attributes: {} },
  isUserPromiseResolved: false,
  onUserUpdateHandlers: [],
  initialConfig: { sdkKey: 'DNNv456Qy6tj6TuosxyyvE' },
  userPromiseResovler: [Function],
  _client:
   Optimizely {
     clientEngine: 'react-sdk',
     clientVersion: '1.0.1',
     errorHandler: NoopErrorHandler {},
     eventDispatcher: { dispatchEvent: [Function: dispatchEvent] },
     __isOptimizelyConfigValid: true,
     logger: OptimizelyLogger { messagePrefix: '' },
     projectConfigManager:
      ProjectConfigManager {
        __updateListeners: [Array],
        jsonSchemaValidator: [Object],
        skipJSONValidation: false,
        __configObj: null,
        datafileManager: [NodeDatafileManager],
        __readyPromise: [Promise] },
     __disposeOnUpdate: [Function: bound ],
     __readyPromise: Promise { <pending> },
     decisionService:
      DecisionService {
        audienceEvaluator: [AudienceEvaluator],
        forcedVariationMap: {},
        logger: [OptimizelyLogger],
        userProfileService: null },
     notificationCenter:
      NotificationCenter {
        logger: [OptimizelyLogger],
        errorHandler: NoopErrorHandler {},
        __notificationListeners: [Object],
        __listenerId: 1 },
     eventProcessor:
      LogTierV1EventProcessor {
        dispatcher: [Object],
        queue: [DefaultEventQueue],
        notificationCenter: [NotificationCenter] },
     __readyTimeouts: { '0': [Object] },
     __nextReadyTimeoutId: 1 },
  userPromise: Promise { <pending> },
  dataReadyPromise: Promise { <pending> } }

React-Redux "connect" not working with "withOptimizely"

I am trying to connect Optimizely with a component connected with react-redux.

I have the following code

export class Report extends Component {
  constructor(props) {
    super(props);
    ....   
}

export default connect(mapStateToProps, { abTestCreate, reportResetErrors })(Report);

I need to connect that component using "withOptimizely", I tried the following 2 approaches and they didn't work, not sure if there is something I can do

const ConnectedReport = connect(mapStateToProps, { abTestCreate, reportResetErrors })(Report);
export default withOptimizely(ConnectedReport);
const OptimizelyReport = withOptimizely(Report);
export default connect(mapStateToProps, { abTestCreate, reportResetErrors })(OptimizelyReport);

Any suggestion about how to make them work together please ?

Types not importable for notification listeners

Hello,

I wanted to attach a notification listener to my team's client instance so we can create an event and pass along to our analytics provider. Specifically, I wanted to attach an ACTIVATE listener. I'd like to create the callback for this outside the call to addNotificationListener and have it be typed. I see the type that this function is expecting is :

NotificationListener<T extends ListenerPayload> = (notificationData: T) => void;

which comes from @optimizely/optimizely-sdk .

The file containing this type also contains other derived types like: ActivateListenerPayload .
While I can derive the less specific type ListenerPayload like this:

type Callback = Parameters<typeof optimizely.notificationCenter.addNotificationListener>[1];

I wish I could import the type from @optimizely/react-sdk via this package , but the types are not exported here.
Furthermore this is the more generic type and what I truly want to use in this case is ActivateListenerPayload .

Is there a reason the types are not exported for use? Or advise what to do in this case to make my function type safe? Thank you!

Allow `default` to be set on an OptimizelyVariation that has `variation` also set

This would be a nice quality of life improvement to have as we often have experiment code that looks like this:

<OptimizelyExperiment experiment="some_test">
  <OptimizelyVariation variation="original">
    <OriginalComponent />
  </OptimizelyVariation>
  <OptimizelyVariation variation="some_variant">
    <VariantComponent />
  </OptimizelyVariation>
  <OptimizelyVariation default>
    <OriginalComponent />
  </OptimizelyVariation>
</OptimizelyExperiment>

It would be nice to be able to express the above as:

<OptimizelyExperiment experiment="some_test">
  <OptimizelyVariation default variation="original">
    <OriginalComponent />
  </OptimizelyVariation>
  <OptimizelyVariation variation="some_variant">
    <VariantComponent />
  </OptimizelyVariation>
</OptimizelyExperiment>

As it is more concise and just as readable.

Is there a chance of seeing this improvement land in the SDK?

-Dave

breaks all existing tests

Adding optimizely rollouts to my react database breaks all my unit and integration tests. how do I mock out the optimizely wrapper in jest?

useDecision not evaluating correctly if user is updated with setUser

After initialization, if I change the user associated with the ReactSDKClient using its setUser method, the decisions produced by useDecision for flagKeys that have been used previously do not evaluate correctly (the userContext for the decision is still the old user).

I think the error is due to the following check: if (!areDecisionInputsEqual(prevDecisionInputs, currentDecisionInputs)) {

The above check doesn't take into consideration the ReactSDKClient's current user.

If I use the overrides in the useDecision call e.g.

const result = useDecision(key, undefined, {
  overrideUserId: OptimizelyClient.user.id,
  overrideAttributes: OptimizelyClient.user.attributes,
});

then everything works as expected. But I shouldn't have to use the overrides.

Thanks.

Ability to turn off INFO logging?

Hi 👋 Is there a way to disable all the INFO logging messages that are output to the browser's console?

[OPTIMIZELY] - INFO  2020-09-09T18:06:27.879Z DatafileManager: Updating datafile from response
[OPTIMIZELY] - INFO  2020-09-09T18:06:27.880Z PROJECT_CONFIG: Skipping JSON schema validation.
[OPTIMIZELY] - INFO  2020-09-09T18:06:27.881Z OPTIMIZELY: Updated Optimizely config to revision 103 (project id 1234)

If not, would you all be open to a PR for this?

Replace @react-native-community/async-storage with @react-native-async-storage/async-storage

In the docs is says

yarn add @react-native-community/async-storage
yarn add @react-native-community/netinfo

However @react-native-community/async-storage is a deprecated project, and has been replaced by @react-native-async-storage/async-storage (with the same API, for now). Please update to use the modern tool. Using optimizely's react sdk in React Native projects will not allow using the new tool, as it expects @react-native-community/async-storage to be present.

Perhaps the best way to build storage in is dependency injection. Storybook is initialized this way, allowing to specify your instance of async storage

import AsyncStorage form "@react-native-async-storage/async-storage";
// or import AsyncStorage from "@react-native-community/async-storage";

getStorybookUI({
  ...
  asyncStorage: AsyncStorage
});

Two different versions of @optimizely/js-sdk-utils in final bundle

Hello!

I'm currently working improving load times of a web-app & noticed thanks to inspectpack that on the app final bundle there are two different versions of @optimizely/js-sdk-utils, 0.1.0 & 0.4.0

see the report here:

image

I could resolve it setting a resolution to always use 0.4.0, but not sure if safe? could lead to bad functioning of the library? Also would like for this library to not introduce duplicates (& increase bundlesize/loadtimes) since I like it & use it on various projects :)

What's a feasible solution? is there any reason in particular @optimizely/react-sdk is still using @optimizely/[email protected] ?

SDK-utils not updated

Getting the error TypeError: Cannot read property 'OPTIMIZELY_CONFIG_UPDATE' of undefined
After installing "@optimizely/js-sdk-utils": "^0.2.0", it works, by default it install v0.1.0

Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'

Happens while building (babel always turns on --isolatedModules flag)

Failed to compile.

./node_modules/@optimizely/optimizely-sdk/lib/core/event_processor/index.ts:25:10
Type error: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.

23 | }
24 |
> 25 | export { EventProcessor, LocalStoragePendingEventsDispatcher } from '@optimizely/js-sdk-event-processor';
|......................^
26 |
27 | export default { createEventProcessor, LocalStoragePendingEventsDispatcher };
28 |

React SDK does not work. Datafile returns empty.

image

I can view the datafile from the browser but when I try and use it in the SDK, I receive the error above. I've tried initiating it with both the sdkKey and datafile but neither works.

My code is simple. Here's the OptimizelyProvider:

<OptimizelyProvider
  optimizely={optimizely}
  user={{ id: 'user123' }}
>

And here's optimizely:

const optimizely = createInstance({
  sdkKey: 'secret',
});

type VariableValuesObject doesn't handle JSON

When a variable is defined as JSON in the optimizely web interface, there is no associated typing for it on VariableValuesObject. However, the SDK handles JSON.parse-ing variables of this type via getFeatureVariableJSON. This leads to a type mismtach when using useFeature or <OptimizelyFeature />.

I might just be missing a key detail here, let me know if I'm using the SDK in an invalid way.

withOptimizely HOC and optimizely onReady state.

Hi, is it correct behaviour that when we use
withOptimizely HOC we always should check props.optimizely for ready state before use ?
I mean

const Menu = props => {
  useEffect(() => {
    // we use 
    props.optimizely.onReady().then(() => {
     console.log(props.optimizely.isFeatureEnabled('feature'));
    });
    
    // instead of using 
    console.log(props.optimizely.isFeatureEnabled('feature'));
  }, []);

  return </>;
};

export default withOptimizely(Menu);

I'm asking because in documentation there is an example without onReady check.
And If we do like in example we've got next error:
OPTIMIZELY: Optimizely object is not valid. Failing isFeatureEnabled.

Also my concern is that when we using OptimizelyFeature component we don't need to do additional checking but for withOptimizely we should. .

ReactSDKClient onDataFileUpdate function

Hi,

I see in the ReactSDKClient there are functions like onUserUpdate that provide a way to get a callback when the user update happens or onReady for when the client initialises. I am wondering if there is a way to add an onDataFileUpdate function that would provide the same functionality but for when an update to the datafile occurs.

For example if I initialise the Optimizely client with:

datafileOptions: {
  autoUpdate: true,
  updateInterval: 1000
}

Then it will poll for datafile updates and if a feature flag has its value changed then it will redownload the new datafile. At this point if any of the <OptimizelyFeature> components have autoUpdate set to true then they will get updated when this new datafile with new flag value is downloaded.

If an onDataFileUpdate function with a callback was provided then we would be able to listen for these same changes using the ReactSDKClient, which allows us to do more with the feature flags, such as push the changes into Redux.

Mocking `isFeatureEnabled` in unit tests

Problem

I'm running unit tests on some components that use feature flags. I want to set all features to enabled every time. I've tried mocking the isFeatureEnabled function but have had no luck so far.

It'd be great if there was a way to configure all flags to be enabled in the createInstance config.

Example

Here's a simplified example of my tests.

import { render, screen } from '@testing-library/react';

export const mockOptimizely = createInstance({});

const MyComponent = () => {
  const [isEnabled] = useFeature('my-feature');

  console.log('isEnabled: ', isEnabled);

  return <div>{isEnabled ? 'Is enabled' : 'Not enabled'}</div>;
};

describe('OptimizelyDependant', () => {
  beforeEach(() => {
    mockOptimizely.isFeatureEnabled = jest.fn().mockReturnValue(true);
  });

  it('passes', () => {
    render(
      <OptimizelyProvider optimizely={mockOptimizely} user={{ id: '123' }}>
        <MyComponent />
      </OptimizelyProvider>
    );
    expect(screen.queryByText('Is enabled')).toBeTruthy();
  });
});

Versions

Package Version
react 17.0.2
@optimizely/react-sdk 2.7.0
jest 26.6.0
@testing-library/react 12.0.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.