{"id":13593022,"url":"https://github.com/antfu/reactivue","last_synced_at":"2025-05-15T07:06:27.269Z","repository":{"id":37383439,"uuid":"280743704","full_name":"antfu/reactivue","owner":"antfu","description":"🙊 Use Vue Composition API in React components","archived":false,"fork":false,"pushed_at":"2024-06-14T17:23:14.000Z","size":1876,"stargazers_count":1451,"open_issues_count":26,"forks_count":38,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-05-10T23:31:38.027Z","etag":null,"topics":["react","vue","vue-composition-api","vue-in-react"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/antfu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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},"funding":{"github":["antfu"],"open_collective":"antfu"}},"created_at":"2020-07-18T21:38:40.000Z","updated_at":"2025-05-07T13:27:08.000Z","dependencies_parsed_at":"2024-01-14T04:36:48.419Z","dependency_job_id":"1335dddc-3928-496d-b194-a0c525d1d4dd","html_url":"https://github.com/antfu/reactivue","commit_stats":{"total_commits":107,"total_committers":8,"mean_commits":13.375,"dds":0.5046728971962617,"last_synced_commit":"8825a00bd647a3ab56a082dc4e980505c4f557ca"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antfu%2Freactivue","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antfu%2Freactivue/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antfu%2Freactivue/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antfu%2Freactivue/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antfu","download_url":"https://codeload.github.com/antfu/reactivue/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254292042,"owners_count":22046426,"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":["react","vue","vue-composition-api","vue-in-react"],"created_at":"2024-08-01T16:01:15.740Z","updated_at":"2025-05-15T07:06:27.218Z","avatar_url":"https://github.com/antfu.png","language":"TypeScript","funding_links":["https://github.com/sponsors/antfu","https://opencollective.com/antfu"],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cimg src=\"./screenshots/logo.svg\" height=\"180\"/\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003eUse Vue Composition API in React components\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://www.npmjs.com/package/reactivue\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/reactivue?color=53c2df\u0026label\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://bundlephobia.com/result?p=reactivue@latest\"\u003e\u003cimg src=\"https://img.shields.io/bundlephobia/minzip/reactivue?color=40b983\u0026label\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\n\u003cpre align=\"center\"\u003e\nnpm i \u003cb\u003ereactivue\u003c/b\u003e\n\u003c/pre\u003e\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\u003cem\u003eI love \u003ca href=\"https://v3.vuejs.org/guide/composition-api-introduction.html\" target=\"_blank\"\u003eVue Composition API\u003c/a\u003e and its \u003ca href=\"https://v3.vuejs.org/guide/reactivity.html\" target=\"_blank\"\u003ereactivity system\u003c/a\u003e, \u003cbr\u003ebut \u003ca href=\"https://reactjs.org/docs/components-and-props.html\" target=\"_blank\"\u003efunctional components\u003c/a\u003e in React are also sweet with Typescript. \u003cbr\u003eInstead of making a choice, why not to use them together?\u003c/em\u003e\u003c/p\u003e\n\n\u003cbr/\u003e\n\n\n## Usage\n\n### Component Factory\n\n```tsx\nimport React from 'React'\nimport { defineComponent, ref, computed, onUnmounted } from 'reactivue'\n\ninterface Props {\n  value: number\n}\n\nconst MyCounter = defineComponent(\n  // setup function in Vue\n  (props: Props) =\u003e {\n    const counter = ref(props.value)\n    const doubled = computed(() =\u003e counter.value * 2)\n    const inc = () =\u003e counter.value += 1\n\n    onUnmounted(() =\u003e console.log('Goodbye World'))\n\n    return { counter, doubled, inc }\n  },\n  // functional component in React\n  ({ counter, doubled, inc }) =\u003e {\n    // you can still use other React hooks\n    return (\n      \u003cdiv\u003e\n        \u003cdiv\u003e{counter} x 2 = {doubled}\u003c/div\u003e\n        \u003cbutton onClick={inc}\u003eIncrease\u003c/button\u003e\n      \u003c/div\u003e\n    )\n  }\n)\n\n// use it as you normally would\nrender(\u003cMyCounter value={10}\u003e, el)\n```\n\n### Hooks\n\nYou can use it as a hook as well.\n\n\u003e The `defineComponent` factory is actually a sugar to and equivalent to the following code.\n\n\n```tsx\nimport React from 'React'\nimport { useSetup, ref, computed, onUnmounted } from 'reactivue'\n\ninterface Props {\n  value: number\n}\n\nfunction MyCounter(Props: Props) {\n  const state = useSetup(\n    (props: Props) =\u003e { // props is a reactive object in Vue\n      const counter = ref(props.value)\n      const doubled = computed(() =\u003e counter.value * 2)\n      const inc = () =\u003e counter.value += 1\n\n      onUnmounted(() =\u003e console.log('Goodbye World'))\n\n      return { counter, doubled, inc }\n    },\n    Props // pass React props to it\n  )\n\n  // state is a plain object just like React state\n  const { counter, doubled, inc } = state\n\n  return (\n    \u003cdiv\u003e\n      \u003cdiv\u003e{counter} x 2 = {doubled}\u003c/div\u003e\n      \u003cbutton onClick={inc}\u003eIncrease\u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n### Hook Factory\n\nTo reuse the composition logics, `createSetup` is provided as a factory to create your own hooks.\n\n```ts\n// mySetup.ts\nimport { createSetup, ref, computed, onUnmounted } from 'reactivue'\n\nexport interface Props {\n  value: number\n}\n\n// create a custom hook that can be reused\nexport const useMySetup = createSetup(\n  (props: Props) =\u003e {\n    const counter = ref(props.value)\n    const doubled = computed(() =\u003e counter.value * 2)\n    const inc = () =\u003e counter.value += 1\n\n    onUnmounted(() =\u003e console.log('Goodbye World'))\n\n    return { counter, doubled, inc }\n  },\n)\n```\n\n```tsx\n// Counter.tsx\nimport React from 'react'\nimport { useMySetup, Props } from './mySetup'\n\nexport const Counter = (props: Props) =\u003e {\n  const { counter, doubled, inc } = useMySetup(props)\n  const { counter: counter2, doubled: doubled2, inc: inc2 } = useMySetup({ value: 10 })\n\n  return (\n    \u003cdiv\u003e\n      \u003cdiv\u003e{counter} x 2 = {doubled}\u003c/div\u003e\n      \u003cbutton onClick={inc}\u003eIncrease\u003c/button\u003e\n      \u003cbr/\u003e\n\n      \u003cdiv\u003e{counter2} x 2 = {doubled2}\u003c/div\u003e\n      \u003cbutton onClick={inc2}\u003eIncrease\u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n## Usage with Preact\n\nTo use reactivue in Preact apps, just replace `reactivue` import with `reactivue/preact`\n\n```diff\nimport { h } from 'preact'\n-import { defineComponent, ref, computed, onUnmounted } from 'reactivue'\n+import { defineComponent, ref, computed, onUnmounted } from 'reactivue/preact'\n```\n\n## Using Vue's Libraries\n\n*Yes, you can!* Before you start, you need set alias in your build tool in order to redirect some apis from `vue` to `reactivue` or `reactivue/preact` if you are using it with Preact.\n\n#### Aliasing\n\n\u003cdetails\u003e\n\u003csummary\u003eVite\u003c/summary\u003e\u003cbr\u003e\n\nAdd following code to `vite.config.js` \n\n```js\n{\n  /* ... */\n  alias: {\n    'vue': 'reactivue',\n    '@vue/runtime-dom': 'reactivue',\n  }\n}\n```\n\nIf you are using it with Preact you have to add following code to `vite.config.js`\n\n```ts\n{\n  /* ... */\n  optimizeDeps: {\n    include: ['reactivue/preact'],\n    exclude: ['@vue/reactivity']\n  }\n}\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003eWebpack\u003c/summary\u003e\u003cbr\u003e\n\nAdd following code to your webpack config\n\n```js\nconst config = { \n  /* ... */\n  resolve: { \n    alias: { \n      'vue': 'reactivue',\n      '@vue/runtime-dom': 'reactivue',\n    },\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eParcel\u003c/summary\u003e\u003cbr\u003e\n\nParcel uses the standard `package.json` file to read configuration options under an `alias` key.\n\n```js\n{\n  \"alias\": {\n    \"vue\": \"reactivue\",\n    \"@vue/runtime-dom\": \"reactivue\",\n  },\n}\n```\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003eRollup\u003c/summary\u003e\u003cbr\u003e\n\nTo alias within Rollup, you'll need to install [@rollup/plugin-alias](https://github.com/rollup/plugins/tree/master/packages/alias). The plugin will need to be placed before your `@rollup/plugin-node-resolve`.\n\n```js\nimport alias from '@rollup/plugin-alias';\n\nmodule.exports = {\n  plugins: [\n    alias({\n      entries: [\n        { find: 'vue', replacement: 'reactivue' },\n        { find: '@vue/runtime-dom', replacement: 'reactivue' }\n      ]\n    })\n  ]\n};\n```\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003eJest\u003c/summary\u003e\u003cbr\u003e\n\nJest allows the rewriting of module paths similar to bundlers. These rewrites are configured using regular expressions in your Jest configuration:\n\n```js\n{\n  \"moduleNameMapper\": {\n    \"^vue$\": \"reactivue\",\n    \"^@vue/runtime-dom$\": \"reactivue\",\n  }\n}\n```\n\n\u003c/details\u003e\n\n#### Installing Vue Plugins\n\nInstalling Vue plugins are almost identical to Vue. Just simply create your root instance with `createApp` function and register your plugins as you do in Vue apps. **You don't need to call `app.mount`**. Your Vue plugins will be available in all your setup functions.\n\n```ts\nimport { createApp } from 'reactivue'\nimport { createPinia } from 'pinia'\n\nconst app = createApp()\n\napp.use(createPinia())\n```\n\n\u003e Note: If you are trying to use a library that calls app.component, app.directive or app.mixin in its install function, reactivue will skip these calls without any action and warn you about it.\n\n#### Compatible Libraries\n\n\u003e A list of libaries that have been tested to work with `reactivue`. Feel free to make PRs adding more.\n\n- [pinia](https://github.com/posva/pinia) - 🍍 Automatically Typed, Modular and lightweight Store for Vue\n- [VueUse](https://github.com/vueuse/vueuse) - 🧰 Collection of Composition API utils for Vue 2 and 3\n- [Villus](https://github.com/logaretm/villus) - 🏎 A tiny and fast GraphQL client for Vue.js\n\n## APIs\n\nSome tips and cavert compare to Vue's Composition API.\n\n#### Reactivity\n\nThe reactivity system APIs are direct re-exported from `@vue/reactivity`, they should work the same as in Vue.\n\n````ts\n// the following two line are equivalent.\nimport { ref, reactive, computed } from 'reactivue'\nimport { ref, reactive, computed } from '@vue/reactivity'\n````\n\n#### Lifecycles\n\nThis library implemented the basic lifecycles to bound with React's lifecycles. For some lifecycles that don't have the React equivalent, they will be called somewhere near when they should be called (for example `onMounted` will be call right after `onCreated`).\n\nFor most of the time, you can use them like you would in Vue.\n\n#### Extra APIs\n\n- `defineComponent()` - not the one you expected to see in Vue. Instead, it accepts a setup function and a render function that will return a React Functional Component.\n- `useSetup()` - the hook for resolve Composition API's setup, refer to the section above.\n- `createSetup()` - a factory to wrapper your logics into reusable custom hooks. \n\n\n#### Limitations\n\n- `getCurrentInstance()` - returns the meta info for the internal states, NOT a Vue instance. It's exposed to allow you check if it's inside a instance scope.\n- `emit()` is not available\n\n\n### Examples\n\n#### Real-world Examples/Showcases\n\n- [Café CN](https://github.com/antfu/awesome-cn-cafe-web) - Web App for Awesome CN Café\n\n- [Preact Browser Example](./examples/preact-htm-browser)\n\n- [React Vite 2.0 Demo](./examples/react-ts-vite)\n\n![image](https://user-images.githubusercontent.com/11247099/88056258-dd7f6980-cb92-11ea-9e89-e090e73b7235.png)\n\n### License\n\n[MIT License](https://github.com/antfu/rectivue/blob/master/LICENSE) © 2020 [Anthony Fu](https://github.com/antfu)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantfu%2Freactivue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantfu%2Freactivue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantfu%2Freactivue/lists"}