npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@lyonbot/reactivue

v0.4.6

Published

Using Vue Composition API in React components.

Downloads

3

Readme

[!NOTE]
This is a modified version by @lyonbot which supports React 18 and @vue/[email protected]

Make reactivity great again!

Usage

Component Factory

import React from 'React'
import { defineComponent, ref, computed, onUnmounted } from '@lyonbot/reactivue'

interface Props {
  value: number
}

const MyCounter = defineComponent(
  // setup function in Vue
  (props: Props) => {
    const counter = ref(props.value)
    const doubled = computed(() => counter.value * 2)
    const inc = () => counter.value += 1

    onUnmounted(() => console.log('Goodbye World'))

    return { counter, doubled, inc }
  },
  // functional component in React
  ({ counter, doubled, inc }) => {
    // you can still use other React hooks
    return (
      <div>
        <div>{counter} x 2 = {doubled}</div>
        <button onClick={inc}>Increase</button>
      </div>
    )
  }
)

// use it as you normally would
render(<MyCounter value={10}>, el)

You can also merge the render function into setup function like this:

const MyCounter = defineComponent(
  // setup function in Vue, returns a render function
  (props: Props) => {
    const counter = ref(props.value)
    const doubled = computed(() => counter.value * 2)
    const inc = () => counter.value += 1

    onUnmounted(() => console.log('Goodbye World'))

    // render function
    return () => {
      return (
        <div>
          <div>{counter.value} x 2 = {doubled.value}</div>
          <button onClick={inc}>Increase</button>
        </div>
      )
    }
  }
)

Hooks

You can use it as a hook as well.

The defineComponent factory is actually a sugar to and equivalent to the following code.

import React from 'React'
import { useSetup, ref, computed, onUnmounted } from '@lyonbot/reactivue'

interface Props {
  value: number
}

function MyCounter(Props: Props) {
  const state = useSetup(
    (props: Props) => { // props is a reactive object in Vue
      const counter = ref(props.value)
      const doubled = computed(() => counter.value * 2)
      const inc = () => counter.value += 1

      onUnmounted(() => console.log('Goodbye World'))

      return { counter, doubled, inc }
    },
    Props // pass React props to it
  )

  // state is a plain object just like React state
  const { counter, doubled, inc } = state

  return (
    <div>
      <div>{counter} x 2 = {doubled}</div>
      <button onClick={inc}>Increase</button>
    </div>
  )
}

Hook Factory

To reuse the composition logics, createSetup is provided as a factory to create your own hooks.

// mySetup.ts
import { createSetup, ref, computed, onUnmounted } from '@lyonbot/reactivue'

export interface Props {
  value: number
}

// create a custom hook that can be reused
export const useMySetup = createSetup(
  (props: Props) => {
    const counter = ref(props.value)
    const doubled = computed(() => counter.value * 2)
    const inc = () => counter.value += 1

    onUnmounted(() => console.log('Goodbye World'))

    return { counter, doubled, inc }
  },
)
// Counter.tsx
import React from 'react'
import { useMySetup, Props } from './mySetup'

export const Counter = (props: Props) => {
  const { counter, doubled, inc } = useMySetup(props)
  const { counter: counter2, doubled: doubled2, inc: inc2 } = useMySetup({ value: 10 })

  return (
    <div>
      <div>{counter} x 2 = {doubled}</div>
      <button onClick={inc}>Increase</button>
      <br/>

      <div>{counter2} x 2 = {doubled2}</div>
      <button onClick={inc2}>Increase</button>
    </div>
  )
}

Usage with Preact

To use reactivue in Preact apps, just replace reactivue import with reactivue/preact

import { h } from 'preact'
-import { defineComponent, ref, computed, onUnmounted } from '@lyonbot/reactivue'
+import { defineComponent, ref, computed, onUnmounted } from 'reactivue/preact'

Using Vue's Libraries

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.

Aliasing

Add following code to vite.config.js

{
  /* ... */
  alias: {
    'vue': '@lyonbot/reactivue',
    '@vue/runtime-dom': '@lyonbot/reactivue',
  }
}

If you are using it with Preact you have to add following code to vite.config.js

{
  /* ... */
  optimizeDeps: {
    include: ['reactivue/preact'],
    exclude: ['@vue/reactivity']
  }
}

Add following code to your webpack config

const config = { 
  /* ... */
  resolve: { 
    alias: { 
      'vue': '@lyonbot/reactivue',
      '@vue/runtime-dom': '@lyonbot/reactivue',
    },
  }
}

Parcel uses the standard package.json file to read configuration options under an alias key.

{
  "alias": {
    "vue": "@lyonbot/reactivue",
    "@vue/runtime-dom": "@lyonbot/reactivue",
  },
}

To alias within Rollup, you'll need to install @rollup/plugin-alias. The plugin will need to be placed before your @rollup/plugin-node-resolve.

import alias from '@rollup/plugin-alias';

module.exports = {
  plugins: [
    alias({
      entries: [
        { find: 'vue', replacement: '@lyonbot/reactivue' },
        { find: '@vue/runtime-dom', replacement: '@lyonbot/reactivue' }
      ]
    })
  ]
};

Jest allows the rewriting of module paths similar to bundlers. These rewrites are configured using regular expressions in your Jest configuration:

{
  "moduleNameMapper": {
    "^vue$": "@lyonbot/reactivue",
    "^@vue/runtime-dom$": "@lyonbot/reactivue",
  }
}

Installing Vue Plugins

Installing 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.

import { createApp } from '@lyonbot/reactivue'
import { createPinia } from 'pinia'

const app = createApp()

app.use(createPinia())

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.

Compatible Libraries

A list of libaries that have been tested to work with reactivue. Feel free to make PRs adding more.

  • pinia - 🍍 Automatically Typed, Modular and lightweight Store for Vue
  • VueUse - 🧰 Collection of Composition API utils for Vue 2 and 3
  • Villus - 🏎 A tiny and fast GraphQL client for Vue.js

APIs

Some tips and cavert compare to Vue's Composition API.

Reactivity

The reactivity system APIs are direct re-exported from @vue/reactivity, they should work the same as in Vue.

// the following two line are equivalent.
import { ref, reactive, computed } from '@lyonbot/reactivue'
import { ref, reactive, computed } from '@vue/reactivity'

Lifecycles

This 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).

For most of the time, you can use them like you would in Vue.

Extra APIs

  • 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.
  • useSetup() - the hook for resolve Composition API's setup, refer to the section above.
  • createSetup() - a factory to wrapper your logics into reusable custom hooks.

Limitations

  • 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.
  • emit() is not available

Examples

Real-world Examples/Showcases

image

License

MIT License © 2020 Anthony Fu