{"id":13514540,"url":"https://github.com/tdeekens/flopflip","last_synced_at":"2026-02-17T15:03:41.383Z","repository":{"id":39641277,"uuid":"98095912","full_name":"tdeekens/flopflip","owner":"tdeekens","description":"🎚Flip or flop features in your React application in real-time backed by flag provider of your choice 🚦","archived":false,"fork":false,"pushed_at":"2025-05-12T07:52:43.000Z","size":43488,"stargazers_count":404,"open_issues_count":5,"forks_count":41,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-12T08:57:08.445Z","etag":null,"topics":["continous-delivery","feature-flags","feature-toggles","hacktoberfest","javascript","launchdarkly","lerna","react","recompose","redux","rollup","splitio"],"latest_commit_sha":null,"homepage":"https://techblog.commercetools.com/embracing-real-time-feature-toggling-in-your-react-application-a5e6052716a9","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tdeekens.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"tdeekens","ko_fi":"tdeekens","custom":"https://paypal.me/tdeekens"}},"created_at":"2017-07-23T12:20:29.000Z","updated_at":"2025-05-12T07:52:47.000Z","dependencies_parsed_at":"2022-07-18T08:13:49.031Z","dependency_job_id":"992d1180-d7c1-426d-95f3-a9420ed715e5","html_url":"https://github.com/tdeekens/flopflip","commit_stats":{"total_commits":2472,"total_committers":33,"mean_commits":74.9090909090909,"dds":0.5914239482200647,"last_synced_commit":"c9be17056eb36b2a0b070c2dbf1dbdf3517f89b2"},"previous_names":[],"tags_count":2055,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdeekens%2Fflopflip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdeekens%2Fflopflip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdeekens%2Fflopflip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdeekens%2Fflopflip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tdeekens","download_url":"https://codeload.github.com/tdeekens/flopflip/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253708826,"owners_count":21951058,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["continous-delivery","feature-flags","feature-toggles","hacktoberfest","javascript","launchdarkly","lerna","react","recompose","redux","rollup","splitio"],"created_at":"2024-08-01T05:00:57.546Z","updated_at":"2026-02-17T15:03:41.326Z","avatar_url":"https://github.com/tdeekens.png","language":"JavaScript","funding_links":["https://github.com/sponsors/tdeekens","https://ko-fi.com/tdeekens","https://paypal.me/tdeekens"],"categories":["Apps","Fully Open-Source Projects","🌐 Web Development - Frontend"],"sub_categories":["Technology-specific Implementations"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"Logo\" src=\"https://raw.githubusercontent.com/tdeekens/flopflip/main/logo.png\" width=\"250\" /\u003e\u003cbr /\u003e\u003cbr /\u003e\n\u003c/p\u003e\n\n\u003ch2 align=\"center\"\u003e🎚 flopflip - Feature Toggling 🚦\u003c/h2\u003e\n\u003cp align=\"center\"\u003e\n  \u003cb\u003eToggle (flip or flop) features being stored in Redux or in a broadcasting system (through the context) via a set of React components or HoCs.\u003c/b\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003csub\u003e\n  ❤️\n  React\n  · Redux\n  · Vitest\n  · Turbo\n  · TypeScript\n  · @testing-library/react\n  · Biome\n  · Babel\n  · Lodash\n  · Changesets\n  · tsup\n  🙏\n  \u003c/sub\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/tdeekens/flopflip/actions?query=workflow%3A%22Test+and+Build%22\"\u003e\n    \u003cimg alt=\"GitHub Action Status\" src=\"https://github.com/tdeekens/flopflip/workflows/test/badge.svg\n\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/tdeekens/flopflip\"\u003e\n    \u003cimg alt=\"Codecov Coverage Status\" src=\"https://img.shields.io/codecov/c/github/tdeekens/flopflip.svg?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://snyk.io/test/github/tdeekens/flopflip\"\u003e\u003cimg src=\"https://snyk.io/test/github/tdeekens/flopflip/badge.svg\" alt=\"Known Vulnerabilities\" data-canonical-src=\"https://snyk.io/test/github/{username}/{repo}\" style=\"max-width:100%;\"/\u003e\u003c/a\u003e\n  \u003cimg alt=\"Made with Coffee\" src=\"https://img.shields.io/badge/made%20with-%E2%98%95%EF%B8%8F%20coffee-yellow.svg\"\u003e\n  \u003cbr /\u003e\u003cbr /\u003e\n  \u003ca href=\"https://techblog.commercetools.com/embracing-real-time-feature-toggling-in-your-react-application-a5e6052716a9\"\u003e\n    Embracing real-time feature toggling in your React application\n  \u003c/a\u003e\u003cbr /\u003e\u003cbr /\u003e\n  \u003ca href=\"https://www.youtube.com/watch?v=x-IqMNFPmkk\"\u003e\n    Feature flagging with LaunchDarkly - Fun Fun Function\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cdetails\u003e\u003cbr /\u003e\u003cbr /\u003e\n  \u003csummary\u003e\u003cb\u003eWant to see a demo?\u003c/b\u003e\u003c/summary\u003e\n\n  \u003cimg alt=\"Logo\" src=\"https://raw.githubusercontent.com/tdeekens/flopflip/main/demo.gif\" /\u003e\n  \u003cbr /\u003e\u003cbr /\u003e\n\u003c/details\u003e\n\n## ❯ Why you might use this.\n\nIn summary feature toggling simplifies and speeds up your development processes. You can ship software more often, release to specified target audiences and test features with users (not only internal staff) before releasing them to everyone.\n\nWith `flopflip` you get many options and ways to toggle features. More elaborate examples below. For now imagine you have a new feature which is not finished developing. However, UX and QA already need access to it. It's hidden by a `\u003cLink\u003e` component redirecting. To toggle it all you need is:\n\n```jsx\n\u003cToggleFeature flag=\"featureFlagName\"\u003e\n  \u003cLink to=\"url/to/new/feature\" /\u003e\n\u003c/ToggleFeature\u003e\n```\n\nHaving `flopflip` setup up you can now target users by whatever you decide to send to e.g. LaunchDarkly. This could be location, hashed E-Mails or any user groups (please respect your user's privacy).\n\nAnother example would be to show a `\u003cbutton\u003e` but disable it for users who should not have access to the feature yet:\n\n```jsx\n\u003cToggleFeature flag=\"featureFlagName\"\u003e\n  {({ isFeatureEnabled }) =\u003e (\n    \u003cbutton disabled={!isFeatureEnabled} onClick={this.handleClick}\u003e\n      Try out feature\n    \u003c/button\u003e\n  )}\n\u003c/ToggleFeature\u003e\n```\n\n...or given you are using a React version with hooks and `@flopflip/react-broadcast` you can:\n\n```jsx\nconst MyFunctionComponent = () =\u003e {\n  const isFeatureEnabled = useFeatureToggle(\"featureFlagName\");\n  const handleClick = () =\u003e console.log(\"🦄\");\n\n  return (\n    \u003cbutton disabled={!isFeatureEnabled} onClick={handleClick}\u003e\n      Try out feature\n    \u003c/button\u003e\n  );\n};\n```\n\nIn all examples flags will update in realtime (depending on the adapter and provider) and the User Interface will update accordingly. If this sounds interesting to you, keep reading.\n\n## ❯ Browser support\n\n```bash\nnpx browserlist\n\nand_chr 110\nchrome 110\nchrome 109\nedge 110\nedge 109\nfirefox 109\nios_saf 16.3\nios_saf 16.2\nios_saf 16.1\nios_saf 16.0\nios_saf 15.6\nsamsung 19.0\n```\n\n## ❯ Package Status\n\n| Package                                                  | Version                                                                                                                                                                                                       | Downloads                                                                                           | Sizes                                                                                              |\n| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |\n| [`react`](/packages/react)                               | [![react Version][react-latest-icon]][react-latest-version] [![react Version][react-next-icon]][react-next-version]                                                                                           | [![react Downloads][react-downloads]][react-downloads]                                              | [![react Minified + GZipped][react-size]][react-size]                                              |\n| [`react-broadcast`](/packages/react-broadcast)           | [![react-broadcast Version][react-broadcast-latest-icon]][react-broadcast-latest-version] [![react-broadcast Version][react-broadcast-next-icon]][react-broadcast-next-version]                               | [![react-broadcast Downloads][react-broadcast-downloads]][react-broadcast-downloads]                | [![react-broadcast Minified + GZipped][react-broadcast-size]][react-broadcast-size]                |\n| [`react-redux`](/packages/react-redux)                   | [![react-redux Version][react-redux-latest-icon]][react-redux-latest-version] [![react-redux Version][react-redux-next-icon]][react-redux-next-version]                                                       | [![react-redux Downloads][react-redux-downloads]][react-redux-downloads]                            | [![react-redux Minified + GZipped][react-redux-size]][react-redux-size]                            |\n| [`launchdarkly-adapter`](/packages/launchdarkly-adapter) | [![launchdarkly-adapter Version][launchdarkly-adapter-latest-icon]][launchdarkly-adapter-latest-version] [![launchdarkly-adapter Version][launchdarkly-adapter-next-icon]][launchdarkly-adapter-next-version] | [![launchdarkly-adapter Downloads][launchdarkly-adapter-downloads]][launchdarkly-adapter-downloads] | [![launchdarkly-adapter Minified + GZipped][launchdarkly-adapter-size]][launchdarkly-adapter-size] |\n| [`splitio-adapter`](/packages/splitio-adapter)           | [![splitio-adapter Version][splitio-adapter-latest-icon]][splitio-adapter-latest-version] [![splitio-adapter Version][splitio-adapter-next-icon]][splitio-adapter-next-version]                               | [![splitio-adapter Downloads][splitio-adapter-downloads]][splitio-adapter-downloads]                | [![splitio-adapter Minified + GZipped][splitio-adapter-size]][splitio-adapter-size]                |\n| [`memory-adapter`](/packages/memory-adapter)             | [![memory-adapter Version][memory-adapter-latest-icon]][memory-adapter-latest-version] [![memory-adapter Version][memory-adapter-next-icon]][memory-adapter-next-version]                                     | [![memory-adapter Downloads][memory-adapter-downloads]][memory-adapter-downloads]                   | [![memory-adapter Minified + GZipped][memory-adapter-size]][memory-adapter-size]                   |\n| [`localstorage-adapter`](/packages/localstorage-adapter) | [![localstorage-adapter Version][localstorage-adapter-latest-icon]][localstorage-adapter-latest-version] [![localstorage-adapter Version][localstorage-adapter-next-icon]][localstorage-adapter-next-version] | [![localstorage-adapter Downloads][localstorage-adapter-downloads]][localstorage-adapter-downloads] | [![localstorage-adapter Minified + GZipped][localstorage-adapter-size]][localstorage-adapter-size] |\n| [`graphql-adapter`](/packages/graphql-adapter)           | [![graphql-adapter Version][graphql-adapter-latest-icon]][graphql-adapter-latest-version] [![graphql-adapter Version][graphql-adapter-next-icon]][graphql-adapter-next-version]                               | [![graphql-adapter Downloads][graphql-adapter-downloads]][graphql-adapter-downloads]                | [![graphql-adapter Minified + GZipped][graphql-adapter-size]][graphql-adapter-size]                |\n| [`cypress-plugin`](/packages/cypress-plugin)             | [![cypress-plugin Version][cypress-plugin-latest-icon]][cypress-plugin-latest-version] [![cypress-plugin Version][cypress-plugin-next-icon]][cypress-plugin-next-version]                                     | [![cypress-plugin Downloads][cypress-plugin-downloads]][cypress-plugin-downloads]                   | [![cypress-plugin Minified + GZipped][localstorage-adapter-size]][localstorage-adapter-size]       |\n| [`types`](/packages/types)                               | [![types Version][types-latest-icon]][types-latest-version] [![types Version][types-next-icon]][types-next-version]                                                                                           | [![types Downloads][types-downloads]][types-downloads]                                              | [![types Minified + GZipped][types-size]][types-size]                                              |\n\n[types-latest-version]: https://flat.badgen.net/npm/v/@flopflip/types\n[types-next-version]: https://flat.badgen.net/npm/v/@flopflip/types\n[types-latest-icon]: https://flat.badgen.net/npm/v/@flopflip/types\n[types-next-icon]: https://flat.badgen.net/npm/v/@flopflip/types/next\n[types-downloads]: https://flat.badgen.net/npm/dm/@flopflip/types\n[types-size]: https://flat.badgen.net/bundlephobia/minzip/@flopflip/types\n[splitio-adapter-latest-version]: https://flat.badgen.net/npm/v/@flopflip/splitio-adapter\n[splitio-adapter-next-version]: https://flat.badgen.net/npm/v/@flopflip/splitio-adapter\n[splitio-adapter-latest-icon]: https://flat.badgen.net/npm/v/@flopflip/splitio-adapter\n[splitio-adapter-next-icon]: https://flat.badgen.net/npm/v/@flopflip/splitio-adapter/next\n[splitio-adapter-downloads]: https://flat.badgen.net/npm/dm/@flopflip/splitio-adapter\n[splitio-adapter-size]: https://flat.badgen.net/bundlephobia/minzip/@flopflip/splitio-adapter\n[launchdarkly-adapter-latest-version]: https://flat.badgen.net/npm/v/@flopflip/launchdarkly-adapter\n[launchdarkly-adapter-next-version]: https://flat.badgen.net/npm/v/@flopflip/launchdarkly-adapter\n[launchdarkly-adapter-latest-icon]: https://flat.badgen.net/npm/v/@flopflip/launchdarkly-adapter\n[launchdarkly-adapter-next-icon]: https://flat.badgen.net/npm/v/@flopflip/launchdarkly-adapter/next\n[launchdarkly-adapter-downloads]: https://flat.badgen.net/npm/dm/@flopflip/launchdarkly-adapter\n[launchdarkly-adapter-size]: https://flat.badgen.net/bundlephobia/minzip/@flopflip/launchdarkly-adapter\n[memory-adapter-latest-version]: https://flat.badgen.net/npm/v/@flopflip/memory-adapter\n[memory-adapter-next-version]: https://flat.badgen.net/npm/v/@flopflip/memory-adapter\n[memory-adapter-latest-icon]: https://flat.badgen.net/npm/v/@flopflip/memory-adapter\n[memory-adapter-next-icon]: https://flat.badgen.net/npm/v/@flopflip/memory-adapter/next\n[memory-adapter-downloads]: https://flat.badgen.net/npm/dm/@flopflip/memory-adapter\n[memory-adapter-size]: https://flat.badgen.net/bundlephobia/minzip/@flopflip/memory-adapter\n[localstorage-adapter-latest-version]: https://flat.badgen.net/npm/v/@flopflip/localstorage-adapter\n[localstorage-adapter-next-version]: https://flat.badgen.net/npm/v/@flopflip/localstorage-adapter\n[localstorage-adapter-latest-icon]: https://flat.badgen.net/npm/v/@flopflip/localstorage-adapter\n[localstorage-adapter-next-icon]: https://flat.badgen.net/npm/v/@flopflip/localstorage-adapter/next\n[localstorage-adapter-downloads]: https://flat.badgen.net/npm/dm/@flopflip/localstorage-adapter\n[localstorage-adapter-size]: https://flat.badgen.net/bundlephobia/minzip/@flopflip/localstorage-adapter\n[graphql-adapter-latest-version]: https://flat.badgen.net/npm/v/@flopflip/graphql-adapter\n[graphql-adapter-next-version]: https://flat.badgen.net/npm/v/@flopflip/graphql-adapter\n[graphql-adapter-latest-icon]: https://flat.badgen.net/npm/v/@flopflip/graphql-adapter\n[graphql-adapter-next-icon]: https://flat.badgen.net/npm/v/@flopflip/graphql-adapter/next\n[graphql-adapter-downloads]: https://flat.badgen.net/npm/dm/@flopflip/graphql-adapter\n[graphql-adapter-size]: https://flat.badgen.net/bundlephobia/minzip/@flopflip/graphql-adapter\n[react-latest-version]: https://flat.badgen.net/npm/v/@flopflip/react\n[react-next-version]: https://flat.badgen.net/npm/v/@flopflip/react\n[react-latest-icon]: https://flat.badgen.net/npm/v/@flopflip/react\n[react-next-icon]: https://flat.badgen.net/npm/v/@flopflip/react/next\n[react-downloads]: https://flat.badgen.net/npm/dm/@flopflip/react\n[react-size]: https://flat.badgen.net/bundlephobia/minzip/@flopflip/react\n[react-broadcast-latest-version]: https://flat.badgen.net/npm/v/@flopflip/react-broadcast\n[react-broadcast-next-version]: https://flat.badgen.net/npm/v/@flopflip/react-broadcast\n[react-broadcast-latest-icon]: https://flat.badgen.net/npm/v/@flopflip/react-broadcast\n[react-broadcast-next-icon]: https://flat.badgen.net/npm/v/@flopflip/react-broadcast/next\n[react-broadcast-downloads]: https://flat.badgen.net/npm/dm/@flopflip/react-broadcast\n[react-broadcast-size]: https://flat.badgen.net/bundlephobia/minzip/@flopflip/react-broadcast\n[react-redux-latest-version]: https://flat.badgen.net/npm/v/@flopflip/react-redux\n[react-redux-next-version]: https://flat.badgen.net/npm/v/@flopflip/react-redux\n[react-redux-latest-icon]: https://flat.badgen.net/npm/v/@flopflip/react-redux\n[react-redux-next-icon]: https://flat.badgen.net/npm/v/@flopflip/react-redux/next\n[react-redux-downloads]: https://flat.badgen.net/npm/dm/@flopflip/react-redux\n[react-redux-size]: https://flat.badgen.net/bundlephobia/minzip/@flopflip/react-redux\n[cypress-plugin-latest-version]: https://flat.badgen.net/npm/v/@flopflip/cypress-plugin\n[cypress-plugin-next-version]: https://flat.badgen.net/npm/v/@flopflip/cypress-plugin\n[cypress-plugin-latest-icon]: https://flat.badgen.net/npm/v/@flopflip/cypress-plugin\n[cypress-plugin-next-icon]: https://flat.badgen.net/npm/v/@flopflip/cypress-plugin/next\n[cypress-plugin-downloads]: https://flat.badgen.net/npm/dm/@flopflip/cypress-plugin\n[cypress-plugin-size]: https://flat.badgen.net/bundlephobia/minzip/@flopflip/cypress-plugin\n\n## ❯ Installation\n\nThis is a mono repository maintained using\n[changesets](https://github.com/atlassian/changesets). It currently contains five\n[packages](/packages) in a `memory-adapter`, a `localstorage-adapter` or\n`launchdarkly-adapter`, `react`, `react-redux` and `react-broadcast`. You should\nnot need the `launchdarkly-adapter` yourself but one of our bindings\n(react-broadcast or react-redux). Both use the `react` package to share\ncomponents.\n\nDepending on the preferred integration (with or without redux) use:\n\n`yarn add @flopflip/react-redux` or `npm i @flopflip/react-redux --save`\n\nor\n\n`yarn add @flopflip/react-broadcast` or `npm i @flopflip/react-broadcast --save`\n\n## ❯ Demo\n\nA minimal [demo](/demo) exists and can be adjusted to point to a\n[custom](https://github.com/tdeekens/flopflip/blob/main/demo/src/App.js#L108)\nLaunchDarkly account. You would have to create feature toggles according to the\nexisting\n[flags](https://github.com/tdeekens/flopflip/blob/main/demo/src/flags.js),\nthough.\n\nThen simply run:\n\n1.  From the repositories root: `yarn build:watch`\n2.  From `/demo`: first `yarn` and then `yarn start`\n\nA browser window should open and the network tab should show feature flags being\nloaded from LaunchDarkly.\n\n## ❯ Documentation\n\nFlopflip allows you to manage feature flags through the notion of adapters (e.g.\nLaunchDarkly or LocalStorage) within an application written using React with or\nwithout Redux.\n\n### `@flopflip/react-redux` \u0026 `@flopflip/react-broadcast` API\n\n- `ConfigureFlopFlip` a component to configure flopflip with an adapter\n  (alternative to the store enhancer)\n- `ReconfigureFlopFlip` a component to reconfigure flopflip with new user properties\n  either merged or overwriting old properties (`shouldOverwrite` prop)\n  - `useAdapterReconfiguration` a hook to reconfigure flopflip with new user properties\n    either merged or overwriting old properties (`shouldOverwrite` prop)\n- `branchOnFeatureToggle` a Higher-Order Component (HoC) to conditionally render\n  components depending on feature toggle state\n- `injectFeatureToggle` a HoC to inject a feature toggle onto the `props` of a\n  component\n- `injectFeatureToggles` a HoC to inject requested feature toggles from existing\n  feature toggles onto the `props` of a component\n- `ToggleFeature` a component conditionally rendering its `children` based on\n  the status of a passed feature flag\n  `\u003cToggleFeature\u003e` child based on the status of its passed feature flag\n- `reducer` and `STATE_SLICE` a reducer and the state slice for the feature\n  toggle state\n- `createFlopFlipEnhancer` a redux store enhancer to configure flipflip and add\n  feature toggle state to your redux store\n\n### Configuration\n\nYou can setup flopflip to work in two ways:\n\n1.  Use React's Context (hidden for you) via `@flopflip/react-broadcast`\n2.  Integrate with Redux via `@flopflip/react-redux`\n\nOften using `@flopflip/react-broadcast` will be the easiest way to get started. You would just need to pick an adapter which can be any of the provided. Either just a `memory-adapter` or an integration with LaunchDarkly via `launchdarkly-adapter` will work. More on how to use [`ConfigureFlopFlip`](#setup-using-components) below.\n\nWhenever you want the flag state to live in Redux you can use `@flopflip/react-redux` which can be setup in two variations itself\n\n1.  Again using [`ConfigureFlopFlip`](#setup-using-components) for simpler use cases, or...\n2.  or with a Redux [`store enhancer`](#setup-through-a-redux-store-enhancer).\n\nThe store enhancer replaces `ConfigureFlopflip` for setup and gives the ability to pass in a `preloadedState` as default flags. For `ConfigureFlopflip` the default flags would be passed as a `defaultFlags`-prop.\n\n#### Setup using Components\n\nSetup is easiest using `ConfigureFlopFlip` which is available in both\n`@flopflip/react-broadcast` and `@flopflip/react-redux`. Feel free to skip this\nsection whenever setup using a store enhancer (in a redux context) is preferred.\n\nIt takes the `props`:\n\n- The `adapter` which can be e.g. `launchdarkly-adapter`\n  - An `adapter` should implement the following methods: `configure` and\n    `reconfigure` which both must return a `Promise` as configuration can be an\n    asynchronous task\n- The `adapterArgs` containing whatever the underlying `adapter` accepts\n  - The `user` object is often the basis to identify an user to toggle features.\n    The user object can contain any additional data.\n  - The `adapter` will receive `onFlagsStateChange` and `onStatusStateChange`\n    will should be invoked accordingly to notify `react-broadcast` and\n    `react-redux` about flag and status changes\n- The `shouldDeferAdapterConfiguration` prop can be used to defer the initial\n  configuration the `adapter`. This might be helpful for cases in which you want\n  to wait for e.g. the `key` to be present within your root component and you do\n  not want `flopflip` to generate a `uuid` for you automatically.\n- The `defaultFlags` prop object can be used to specify default flag values\n  until an `adapter` responds or in case flags were removed\n- The adapters expose function to update flags explicitely via `adapter.updateFlags`\n  which eases updating flags and flushes them to all components via\n  `react-broadcast` or `react-redux`\n\n**Different adapters allow for different configurations:**\n\nPlease note that all adapters accept a `user: TUser` which has an optional `key` of type string. This `user` attribute can be used by each adapter to identify a user uniquely. Some adapters which require a `user.key` will generate a uuid whenever no `key` is passed.\n\n_1. The `@flopflip/launchdarkly-adapter` accepts_\n\n- `sdk.clientSideId`: The client side id of LaunchDarkly\n- `sdk.clientOptions`: additional options to be passed to the underlying SDK\n- `flags`: defaulting to `null` to subscribe only to specific flags. Helpful when not wanting to subscribe to all flags to utilise LaunchDarkly's automatic flag archiving functionality\n- `cacheMode`: defaulting to `null` to change application of cached flags\n  - The value can be `eager` to indicate that remote values should have effect immediately\n  - The value can be `lazy` to indicate that values should be updated in the cache but only be applied once the adapter is configured again\n- `throwOnInitializationFailure`: defaulting to `false` to indicate if the adapter just re-throw an error during initialization\n- `flagsUpdateDelayMs`: defaulting to `0` to debounce the flag update subscription\n\n_2. The `@flopflip/splitio-adapter` accepts_\n\n- `sdk.authorizationKey`: Authorization key for splitio\n- `sdk.options`: General attributes passed to splitio SDK\n- `sdk.treatmentAttributes`: The treatment attributes passed to splitio\n\n_3. The `@flopflip/graphql-adapter` accepts_\n\n- `uri`: the `uri` to the GraphQL endpoint so e.g. `https://graphql.com/graphql`\n- `query`: the GraphQL query which returns features for instance `query AllFeatures { flags: allFeatures { name \\n value} }`\n- `getQueryVariables`: a function called with `adapterArgs` being variables to your GraphQL query\n- `getRequestHeaders`: a function called with `adapterArgs` being headers to your GraphQL request\n- `parseFlags`: a function called with the `data` of fetched flags to parse the result before being exposed to your application. This function should be used to parse a query response into the `TFlags` type.\n- `fetcher`: a fetch implemtation if you prefer to not rely on the global `fetch`\n- `pollingIntervalMs`: the polling interval to check for updated flag values\n\n_4. The `@flopflip/localstorage-adapter` accepts_\n\n- `pollingIntervalMs`: an interval at which the adapter polls for new flags from localstorage in milliseconds\n\n_5. The `@flopflip/memory-adapter` accepts_\n\nNo special configuration is required for the memory adapter at this point.\n\nWhenever you do not want to have the state of all flags persisted in redux the\nminimal configuration for a setup with `@flopflip/react-broadcast` and\nLaunchDarkly would be nothing more than:\n\n```js\nimport { ConfigureFlopFlip } from \"@flopflip/react-redux\";\nimport { adapter } from \"@flopflip/launchdarkly-adapter\";\n// or import { adapter } from '@flopflip/memory-adapter';\n// or import { adapter } from '@flopflip/localstorage-adapter';\n\n\u003cConfigureFlopFlip\n  adapter={adapter}\n  adapterArgs={{ sdk: { clientSideId }, user }}\n\u003e\n  \u003cApp /\u003e\n\u003c/ConfigureFlopFlip\u003e;\n```\n\nYou can also pass `render` or `children` as a function to act differently based on the underlying adapter's ready state:\n\n```jsx\n\u003cConfigureFlopFlip\n  adapter={adapter}\n  adapterArgs={{ sdk: { clientSideId }, user }}\n\u003e\n  {(isAdapterConfigured) =\u003e\n    isAdapterConfigured ? \u003cApp /\u003e : \u003cLoadingSpinner /\u003e\n  }\n\u003c/ConfigureFlopFlip\u003e\n```\n\n```jsx\n\u003cConfigureFlopFlip\n  adapter={adapter}\n  adapterArgs={{ sdk: { clientSideId }, user }}\n  render={() =\u003e \u003cApp /\u003e}\n/\u003e\n```\n\nNote that `children` will be called with a loading state prop while `render` will only be called when the adapter is configured. This behaviour mirrors the workings of `\u003cToggleFeature\u003e`.\n\nThis variant of the `ConfigureFlopFlip` component form\n`@flopflip/react-broadcast` will use the context and a broadcasting system to\nreliably communicate with children toggling features (you do not have to worry\nabout any component returning `false` from `shouldComponentUpdate`). If you're using `@flopflip/react-broadcast` you're done already.\n\nGiven your preference is to have the feature flag's state persisted in redux you\nwould simply add a reducer when creating your store.\n\n```js\nimport { configureStore, combineReducers } from \"@reduxjs/toolkit\";\nimport {\n  ConfigureFlopFlip,\n  flopflipReducer,\n  FLOPFLIP_STATE_SLICE,\n} from \"@flopflip/react-redux\";\n\n// Maintained somewhere within your application\nimport { user } from \"./user\";\nimport { appReducer } from \"./reducer\";\n\nconst rootReducer = combineReducers({\n  appReducer,\n  [FLOPFLIP_STATE_SLICE]: flopflipReducer,\n});\n\nconst store = configureStore({\n  reducer: rootReducer,\n  middleware: (getDefaultMiddleware) =\u003e getDefaultMiddleware(),\n  preloadedState: initialState,\n});\n\nexport default store;\n```\n\n#### Setup through a Redux store enhancer\n\nAnother way to configure `flopflip` is using a store enhancer. For this a\n`flopflip` reducer should be wired up with a `combineReducers` within your\napplication in coordination with the `STATE_SLICE` which is used internally too\nto manage the location of the feature toggle states. This setup eliminates the\nneed to use `ConfigureFlopFlip` somewhere else in your application's component\ntree.\n\nIn context this configuration could look like\n\n```js\nimport { configureStore, combineReducers } from \"@reduxjs/toolkit\";\nimport {\n  createFlopFlipEnhancer,\n  flopflipReducer,\n  FLOPFLIP_STATE_SLICE,\n} from \"@flopflip/react-redux\";\nimport { adapter } from \"@flopflip/launchdarkly-adapter\";\n\n// Maintained somewhere within your application\nimport { user } from \"./user\";\nimport { appReducer } from \"./reducer\";\n\nconst rootReducer = combineReducers({\n  appReducer,\n  [FLOPFLIP_STATE_SLICE]: flopflipReducer,\n});\n\nconst store = configureStore({\n  reducer: rootReducer,\n  middleware: (getDefaultMiddleware) =\u003e\n    getDefaultMiddleware().concat(\n      createFlopFlipEnhancer(adapter, {\n        sdk: { clientSideId: window.application.env.LD_CLIENT_ID },\n        user,\n      })\n    ),\n  preloadedState: initialState,\n});\n\nexport default store;\n```\n\nNote that `@flopflip/react-redux` also exports a `createFlopflipReducer(preloadedState: Flags)`. This is useful when you want to populate the redux store with initial values for your flags.\n\nExample:\n\n```js\nconst defaultFlags = { flagA: true, flagB: false };\n\nconst rootReducer = combineReducers({\n  appReducer,\n  [FLOPFLIP_STATE_SLICE]: createFlopflipReducer(defaultFlags),\n});\n\nconst store = configureStore({\n  reducer: rootReducer,\n});\n```\n\nThis way you can pass `defaultFlags` as the `preloadedState` directly into the `flopflipReducer`. This means you do not need to keep track of it in your applications's `initialState` as in the following anti-pattern example:\n\n```js\nconst initialState = {\n  [FLOPFLIP_STATE_SLICE]: { flagA: true, flagB: false },\n};\n\nconst rootReducer = combineReducers({\n  appReducer,\n  [FLOPFLIP_STATE_SLICE]: flopflipReducer,\n});\n\nconst store = configureStore({\n  reducer: rootReducer,\n  preloadedState: initialState,\n});\n```\n\n#### Syncing the store reducer with adapters\n\nIn addition to initiating `flopflip` when creating your store, you could still wrap most or all of your application's tree in\n`ConfigureFlopFlip`. This is needed when you want to identify as a user and setup the integration with LaunchDarkly or any other flag provider or adapter.\n\nNote: This is not needed when using the memory-adapter.\n\n```js\nimport adapter from \"@flopflip/launchdarkly-adapter\";\n\n\u003cConfigureFlopFlip\n  adapter={adapter}\n  adapterArgs={{ sdk: { clientSideId }, user }}\n\u003e\n  \u003cApp /\u003e\n\u003c/ConfigureFlopFlip\u003e;\n```\n\nWhenever your application \"gains\" certain information (e.g. with `react-router`) only further\ndown the tree but that information should be used for user targeting (through `adapterArgs.user`) you\ncan use `ReconfigureFlopflip`. `ReconfigureFlopflip` itself communicates with `ConfigureFlopflip`\nto reconfigure the given adapter for more fine grained targeting with the passed `user`.\nYou also do not have to worry about rendering any number of `ReconfigureFlopflip`s before the adapter is\ninitialized (e.g. LaunchDarkly). Requested reconfigurations will be queued and processed once the adapter is configured.\n\nImagine having `ConfigureFlopflip` above a given component wrapped by a `Route`:\n\n```jsx\n\u003cConfigureFlopFlip\n  adapter={adapter}\n  adapterArgs={{ sdk: { clientSideId }, user }}\n\u003e\n  \u003c\u003e\n    \u003cSomeOtherAppComponent /\u003e\n    \u003cRoute\n      exact={false}\n      path=\"/:projectKey\"\n      render={(routerProps) =\u003e (\n        \u003c\u003e\n          \u003cMyRouteComponent /\u003e\n          \u003cReconfigureFlopflip\n            // Note: This is the default - feel free to omit unless you want to set it to `true`.\n            shouldOverwrite={false}\n            // Note: this should be memoised to not trigger wasteful `reconfiguration`s.\n            user={{ projectKey: routerProps.projectKey }}\n          /\u003e\n        \u003c/\u003e\n      )}\n    /\u003e\n  \u003c/\u003e\n\u003c/ConfigureFlopFlip\u003e\n```\n\nInternally, `ReconfigureFlopFlip` will pass the `projectKey` to `ConfigureFlopFlip`, causing the adapter to automatically update the user context and therefore to flush new flags from the adapter (given they are provided by e.g. LaunchDarkly).\n\n_Note:_ Whenever `shouldOverwrite` is `true` the existing user configuration will be overwritten not merged. Use with care as any\nsubsequent `shouldOverwrite={true}` will overwrite any previously passed `user` with `shouldOverwrite={false}` (default).\n\n### `@flopflip/react-broadcast` \u0026 `@flopflip/react-redux` API\n\nApart from `ConfigureFlopFlip` both packages `@flopflip/react-broadcast` and\n`@flopflip/react-redux` export the same set of components to toggle based on\nfeatures. Only the import changes depending on if you chose to integrate with\nredux or without. Again, behind the scenes the build on `@flopflip/react` to\nshare common logic.\n\n- `useFeatureToggle` a React hook to read a single flag\n- `useFeatureToggles` a React hook to read multiple flags at once\n- `useFlagVariation` a React hook to read a single variation of a flag\n- `useFlagVariations` a React hook to read multiple variations of a flag at once\n- `useAdapterStatus` a React hook to read the underlying adapter's status\n- `branchOnFeatureToggle` a Higher-Order Component (HoC) to conditionally render\n  components depending on feature toggle state\n- `injectFeatureToggle` a HoC to inject a feature toggle onto the `props` of a\n  component\n- `injectFeatureToggles` a HoC to inject requested feature toggles from existing\n  feature toggles onto the `props` of a component\n- `ToggleFeature` a component conditionally rendering its `children` based on\n  the status of a passed feature flag\n\n[Note:](#flag-normalization) that all passed `flagNames` passed as `flag` are a string. Depending on the adapter used _these are normalized_ to be camel cased. This means that whenever a `foo-flag-name` is received in e.g. LaunchDarkly or splitio it will be converted to `fooFlagName`. The same applies for a `foo_flag_name`. This is meant to help using flags in an adapter agnostic way. Whenever a flag is passed in the non-normalized form it is also normalized again. Lastly, `flopflip` will show a warning message in the console in development mode whenever a non normalized flag name is passed.\n\n#### `useFeatureToggle(flagName: string, flagVariation: FlagVariation): boolean`\n\nGiven you want to use React hooks within a functional component you can toggle as follows:\n\n```js\nimport { useFeatureToggle } from '@flopflip/react-broadcast';\n\nconst ComponentWithFeatureToggle = props =\u003e {\n   const isFeatureEnabled = useFeatureToggle('myFeatureToggle');\n\n   return (\n     \u003ch3\u003e{props.title}\u003ch3\u003e\n     \u003cp\u003e\n       The feature is {isFeatureEnabled ? 'enabled' : 'disabled'}\n     \u003c/p\u003e\n   );\n}\n```\n\n#### `useFeatureToggles({ [ flagName: string ]: FlagVariation } ): boolean[]`\n\nGiven you want to use React hooks within a functional component you can toggle multiple flags at once as follows:\n\n```js\nimport { useFeatureToggles } from '@flopflip/react-broadcast';\n\nconst ComponentWithFeatureToggles = props =\u003e {\n   const [isFirstFeatureEnabled, isV2SignUpEnabled] = useFeatureToggles({\n     'myFeatureToggle': true,\n     'mySignUpVariation': 'signUpV2',\n   });\n\n   return (\n     \u003ch3\u003e{props.title}\u003ch3\u003e\n     \u003cp\u003e\n       The first feature is {isFirstFeatureEnabled ? 'enabled' : 'disabled'}\n     \u003c/p\u003e\n     \u003cp\u003e\n       The v2 signup feature is {isV2SignUpEnabled ? 'enabled' : 'disabled'}\n     \u003c/p\u003e\n   );\n}\n```\n\n#### `useFlagVariation(flagName: string): FlagVariation`\n\nGiven you want to use React hooks within a functional component you can read a variation as follows:\n\n```js\nimport { useFlagVariation } from '@flopflip/react-broadcast';\n\nconst ComponentWithFeatureToggle = props =\u003e {\n   const featureVariation = useFlagVariation('myFeatureToggle');\n\n   return (\n     \u003ch3\u003e{props.title}\u003ch3\u003e\n     \u003cp\u003e\n       The feature variation is {featureVariation}\n     \u003c/p\u003e\n   );\n}\n```\n\n#### `useFlagVaritions([flagName: string]): FlagVariation[]`\n\nGiven you want to use React hooks within a functional component you can read multiple variations as follows:\n\n```js\nimport { useFlagVariations } from '@flopflip/react-broadcast';\n\nconst ComponentWithFeatureToggle = props =\u003e {\n   const [featureVariation1, featureVariation2] = useFlagVariations(['myFeatureToggle1', 'myFeatureToggle2']);\n\n   return (\n     \u003ch3\u003e{props.title}\u003ch3\u003e\n     \u003cul\u003e\n        \u003cli\u003e\n          The feature variation 1 is {featureVariation1}\n        \u003c/li\u003e\n        \u003cli\u003e\n          The feature variation 2 is {featureVariation2}\n        \u003c/li\u003e\n     \u003c/ul\u003e\n   );\n}\n```\n\n#### `useAdapterStatus(): AdapterStatus`\n\nGiven you want to use React hooks within a functional component you can read the adapter status as follows:\n\n```js\nimport { useAdapterStatus } from \"@flopflip/react-broadcast\";\n\nconst ComponentWithFeatureToggle = () =\u003e {\n  const isFeatureEnabled = useFeatureToggle(\"myFeatureToggle\");\n  const { isConfigured } = useAdapterStatus();\n\n  if (!isConfigured) return \u003cLoadingSpinner /\u003e;\n  else if (!isFeatureEnabled) \u003cPageNotFound /\u003e;\n  else return \u003cFeatureComponent /\u003e;\n};\n```\n\n#### `ToggleFeature`\n\nThe component renders its `children` depending on the state of a given feature\nflag. It also allows passing an optional `untoggledComponent` which will be\nrendered whenever the feature is disabled instead of `null`.\n\n```js\nimport React, { Component } from \"react\";\nimport { ToggleFeature } from \"@flopflip/react-redux\";\n// or import { ToggleFeature } from '@flopflip/react-broadcast';\nimport { flagsNames } from \"./feature-flags\";\n\nconst UntoggledComponent = () =\u003e \u003ch3\u003e{\"At least there is a fallback!\"}\u003c/h3\u003e;\nexport default (\n  \u003cToggleFeature\n    flag={flagsNames.THE_FEATURE_TOGGLE}\n    untoggledComponent={UntoggledComponent}\n  \u003e\n    \u003ch3\u003eI might be gone or there!\u003c/h3\u003e\n  \u003c/ToggleFeature\u003e\n);\n```\n\nor with for multi variate feature toggles:\n\n```js\nconst UntoggledComponent = () =\u003e \u003ch3\u003e{\"At least there is a fallback!\"}\u003c/h3\u003e;\n\nexport default (\n  \u003cToggleFeature\n    flag={flagsNames.THE_FEATURE_TOGGLE.NAME}\n    variation={flagsNames.THE_FEATURE_TOGGLE.VARIATES.A}\n    untoggledComponent={UntoggledComponent}\n  \u003e\n    \u003ch3\u003eI might be gone or there!\u003c/h3\u003e\n  \u003c/ToggleFeature\u003e\n);\n```\n\nor with `toggledComponent` prop:\n\n```js\nconst UntoggledComponent = () =\u003e \u003ch3\u003e{\"At least there is a fallback!\"}\u003c/h3\u003e;\nconst ToggledComponent = () =\u003e \u003ch3\u003e{\"I might be gone or there!\"}\u003c/h3\u003e;\n\nexport default (\n  \u003cToggleFeature\n    flag={flagsNames.THE_FEATURE_TOGGLE.NAME}\n    variation={flagsNames.THE_FEATURE_TOGGLE.VARIATES.A}\n    untoggledComponent={UntoggledComponent}\n    toggledComponent={ToggledComponent}\n  /\u003e\n);\n```\n\nor with Function as a Child (FaaC) which is always invoked with an `isFeatureEnabled` argument:\n\n```js\nconst UntoggledComponent = () =\u003e \u003ch3\u003e{\"At least there is a fallback!\"}\u003c/h3\u003e;\n\nexport default (\n  \u003cToggleFeature\n    flag={flagsNames.THE_FEATURE_TOGGLE.NAME}\n    variation={flagsNames.THE_FEATURE_TOGGLE.VARIATES.A}\n    untoggledComponent={UntoggledComponent}\n  \u003e\n       {({ isFeatureEnabled }) =\u003e \u003ch3\u003eI might be gone or there!\u003c/h3\u003e}\n  \u003c/ToggleFeature\u003e\n);\n```\n\nor with a `render` prop. Note that the `render` prop will only be invoked then the feature is turned on:\n\n```js\nconst UntoggledComponent = () =\u003e \u003ch3\u003e{\"At least there is a fallback!\"}\u003c/h3\u003e;\n\nexport default (\n  \u003cToggleFeature\n    flag={flagsNames.THE_FEATURE_TOGGLE.NAME}\n    variation={flagsNames.THE_FEATURE_TOGGLE.VARIATES.A}\n    untoggledComponent={UntoggledComponent}\n    render={() =\u003e \u003ch3\u003eI might be gone or there!\u003c/h3\u003e}\n  /\u003e\n);\n```\n\nthis last example will always turn the feature on if the variation or toggle\ndoes not exist. For this also look at `defaultFlags` for `ConfigureFlopFlip`.\n\nWe actually recommend maintaining a list of constants with feature flag names\nsomewhere within your application. This avoids typos and unexpected behavior.\nAfter all, the correct workings of your feature flags is crutial to your\napplication.\n\n#### `branchOnFeatureToggle({ flag: String, variation?: String | Boolean })`\n\nA HoC to conditionally render a component based on a feature toggle's state. It\naccepts the feature toggle name and an optional component to be rendered in case\nthe feature is disabled.\n\nWithout a component rendered in place of the `ComponentToBeToggled`:\n\n```js\nimport { branchOnFeatureToggle } from \"@flopflip/react-redux\";\nimport flagsNames from \"./feature-flags\";\n\nconst ComponentToBeToggled = () =\u003e \u003ch3\u003eI might be gone or there!\u003c/h3\u003e;\n\nexport default branchOnFeatureToggle({ flag: flagsNames.THE_FEATURE_TOGGLE })(\n  ComponentToBeToggled\n);\n```\n\nWith a component rendered in place of the `ComponentToBeToggled`:\n\n```js\nimport { branchOnFeatureToggle } from \"@flopflip/react-redux\";\nimport { flagsNames } from \"./feature-flags\";\n\nconst ComponentToBeToggled = () =\u003e \u003ch3\u003eI might be gone or there!\u003c/h3\u003e;\nconst ComponentToBeRenderedInstead = () =\u003e (\n  \u003ch3\u003eAt least there is a fallback!\u003c/h3\u003e\n);\n\nexport default branchOnFeatureToggle(\n  { flag: flagsNames.THE_FEATURE_TOGGLE },\n  ComponentToBeRenderedInstead\n)(ComponentToBeToggled);\n```\n\nor when the flag is multi variation\n\n```js\nimport { branchOnFeatureToggle } from \"@flopflip/react-redux\";\nimport { flagsNames } from \"./feature-flags\";\n\nconst ComponentToBeToggled = () =\u003e \u003ch3\u003eI might be gone or there!\u003c/h3\u003e;\nconst ComponentToBeRenderedInstead = () =\u003e (\n  \u003ch3\u003eAt least there is a fallback!\u003c/h3\u003e\n);\n\nexport default branchOnFeatureToggle(\n  {\n    flag: flagsNames.THE_FEATURE_TOGGLE,\n    variation: \"variate1\",\n  },\n  ComponentToBeRenderedInstead\n)(ComponentToBeToggled);\n```\n\n#### `injectFeatureToggles(flagNames: Array\u003cString\u003e, propKey?: String, areOwnPropsEqual?: Function)`\n\nThis HoC matches feature toggles given against configured ones and injects the\nmatching result.\n\n```js\nimport { injectFeatureToggles } from \"@flopflip/react-redux\";\nimport { flagsNames } from \"./feature-flags\";\n\nconst Component = (props) =\u003e {\n  if (props.featureToggles[flagsNames.TOGGLE_A])\n    return \u003ch3\u003eSomething to render!\u003c/h3\u003e;\n  else if (props.featureToggles[flagsNames.TOGGLE_B])\n    return \u003ch3\u003eSomething else to render!\u003c/h3\u003e;\n\n  return \u003ch3\u003eSomething different to render!\u003c/h3\u003e;\n};\n\nexport default injectFeatureToggles([flagsNames.TOGGLE_A, flagsNames.TOGGLE_B])(\n  Component\n);\n```\n\n#### `injectFeatureToggle(flag: String, propKey?: String)`\n\nThis HoC matches feature toggles given against configured ones and injects the\nmatching result. `branchOnFeatureToggle` uses this to conditionally render a\ncomponent. You also may pass a second argument to overwrite the default\n`propKey` of the injected toggle (defaults to `isFeatureEnabled`).\n\n```js\nimport { injectFeatureToggle } from \"@flopflip/react-redux\";\nimport { flagsNames } from \"./feature-flags\";\n\nconst Component = (props) =\u003e {\n  if (props.isFeatureEnabled) return \u003ch3\u003eSomething to render!\u003c/h3\u003e;\n\n  return \u003ch3\u003eSomething different to render!\u003c/h3\u003e;\n};\n\nexport default injectFeatureToggle(flagsNames.TOGGLE_B)(Component);\n```\n\nThe feature flags will be available as `props` within the component allowing\nsome custom decisions based on their value.\n\n### Additional `@flopflip/react-redux` API\n\nWe also expose our internal selectors to access feature toggle(s) directly so\nthat the use of `injectFeatureToggle` or `injectFeatureToggles` is not enforced\nor the only value to access flags from `@flopflip/react-redux`'s store slice.\nThe two selectors `selectFeatureFlag` and `selectFeatureFlags` return the same\nvalues for flags as `injectFeatureToggle` and `injectFeatureToggles` would.\n\nAn example usage for a connected component would be:\n\n```js\nimport { selectFeatureFlag } from \"@flopflip/react-redux\";\n\nconst mapStateToProps = (state) =\u003e ({\n  someOtherState: state.someOtherState,\n  isFeatureOn: selectFeatureFlag(\"fooFlagName\")(state),\n});\n\nexport default connect(mapStateToProps)(FooComponent);\n```\n\nas an alternative to using `injectFeatureToggle`:\n\n```js\nconst mapStateToProps = state =\u003e ({\n  someOtherState: state.someOtherState,\n})\n\nexport default compose(\n  injectFeatureToggle('fooFlagName')\n  connect(mapStateToProps)\n)(FooComponent)\n```\n\nThe same example above applies for `selectFeatureFlags`.\n\n#### `createFlopFlipEnhancer`\n\nRequires arguments of `clientSideId:string`, `user:object`.\n\n- The `adapter`\n- The `adapterArgs` object\n  - Often with the before mentioned user object `user` object which often needs\n    at least a `key` attribute\n\n### `@flopflip/cypress-plugin`\n\n#### Introduction\n\nChanging flag state in End-to-End test runs helps ensuring that an application works as expected with all variations of a feature. For this `@flopflip` comes with a `cypress-plugin`. This plugin tightly integrates with any underlying adapter and allows altering flag state from within test runs.\n\nImagine having the following Cypress test suite:\n\n```js\ndescribe(\"adding users\", () =\u003e {\n  describe(\"with seaching by E-Mail being enabled\", () =\u003e {\n    it(\"should allow adding users by E-Mail\", () =\u003e {\n      cy.updateFeatureFlags({ searchUsersByEmail: true });\n\n      //... expectations\n    });\n  });\n  describe(\"with seaching by E-Mail being disabled\", () =\u003e {\n    it(\"should allow adding users by name\", () =\u003e {\n      cy.updateFeatureFlags({ searchUsersByEmail: false });\n\n      //... expectations\n    });\n  });\n});\n```\n\nIn the example above we test two variations of a feature. Being able to alter flag state during test runs avoids work-arounds such as complex multi-project setups and makes the tests themselves resilient to changes of your flag configurations on your staging or testing environments.\n\n#### Installation\n\nTo install the `@flopflip/cypress-plugin` you will have to add the respective command and plugin as follows after installing it as a `devDependency`.\n\n```bash\nyarn add --dev @floplfip/cypress-plugin\nnpm install --save-dev @floplfip/cypress-plugin\n```\n\nIn the `plugins/index.js` add the following to your existing config:\n\n```diff\n+const flopflipCypressPlugin = require('@flopflip/cypress-plugin');\n\nmodule.exports = (on, cypressConfig) =\u003e {\n\n+flopflipCypressPlugin.install(on);\n\n  return { };\n};\n```\n\nIn the `support/index.js` add the following to your existing commands:\n\n```js\nimport { addCommands as addFlopflipCommands } from \"@flopflip/cypress-plugin\";\n\naddFlopflipCommands({\n  adapterId: \"launchdarkly\",\n});\n```\n\nPlease note that the `adapterId` should be one of `launchdarkly`, `memory`, `localstorage` or `splitio`. It allows the `cypress-plugin` to hook into the respective adapter. Also make sure to update to the most recent version of any adapter to ensure a smooth integration between the plugin and the adapter.\n\n### Module formats\n\n`@flopflip/react-redux` and `@flopflip/react-broadcast` is built for UMD (un-\nand minified) and ESM using\n[`rollup`](https://github.com/tdeekens/flopflip/blob/main/rollup.config.js).\n\nBoth our `@flopflip/launchdarkly-wrapper` and `@flopflip/react` packages are\n\"only\" build for ESM and CommonJS (not UMD) as they are meant to be consumed by\na module loader to be integrated.\n\nThe `package.json` files contain a `main` and `module` entry to point to a\nCommonJS and ESM build.\n\n- ...ESM just import the `dist/@flopflip/\u003cpackage\u003e.es.js` within your app.\n  - ...it's a transpiled version accessible via the `pkg.module`\n- ...CommonJS use the `dist/@flopflip/\u003cpackage\u003e.cjsjs`\n- ...AMD use the `dist/@flopflip/\u003cpackage\u003e.umd.js`\n- ...`\u003cscript /\u003e` link it to `dist/@flopflip/\u003cpackage\u003e.umd.js` or\n  `dist/@flopflip/\u003cpackage\u003e.umd.min.js`\n\nAll build files are part of the npm distribution using the\n[`files`](https://github.com/tdeekens/flopflip/blob/main/packages/react-redux/package.json)\narray to keep install time short.\n\nAlso feel free to use\n[unpkg.com](https://unpkg.com/@flopflip/react-redux@latest/dist/@flopflip-react-redux.umd.min.js)\nas a CDN to the [dist](https://unpkg.com/@flopflip/react-redux@latest/dist/)\nfiles.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftdeekens%2Fflopflip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftdeekens%2Fflopflip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftdeekens%2Fflopflip/lists"}