DEV Community

Cover image for How to render React components in Vue
Amir Adel
Amir Adel

Posted on

How to render React components in Vue

You might be wondering, how is it possible to use React and Vue in the same application? Well, after all, React and Vue are two different libraries, but they are both JavaScript libraries. Components you write in JSX and Vue are compiled down to JavaScript render functions. So, technically, it is possible to combine JavaScript with JavaScript.

Why?

Sometimes, we may want to create a UI library that can be integrated with any JavaScript UI library or framework. In such cases, we need to have a core that aligns with our favorite UI library or framework and create connectors for other UI libraries or frameworks so that our package can function seamlessly in any environment.

Setup

  1. Create a new Vue app with vite:

     # TypeScript
     npm create vite@latest my-vue-react-app -- --template vue-ts
     # JavaScript
     npm create vite@latest my-vue-react-app -- --template vue
    
  2. Install reactand and react-dom as dependencies :

     npm i react react-dom
    
  3. Install @vitejs/plugin-react as devDependencies :

     npm install @vitejs/plugin-react --save-dev
    
  4. Update vite.config:

     // ./vite.config.ts
     import { defineConfig } from 'vite'
     import vue from '@vitejs/plugin-vue'
     import react from '@vitejs/plugin-react'
    
     export default defineConfig({
       plugins: [vue(),react()],
     })
    
  5. If you are using TypeScript, then install the necessary types for React and react-dom:

     npm install @types/react @types/react-dom --save-dev
    

1.Create a react Component

// .scr/components/ReactComponent.tsx

import React from 'react'

export const ReactComponent:React.FC =()=>{
    return (
        <button>React Button</button>
    )
}
Enter fullscreen mode Exit fullscreen mode

2.Create A Vanilla Connector

From a low-level perspective, a React component is simply a JavaScript function. Therefore, we are essentially passing a basic JavaScript function to react-dom.
So now what we can do is create a vanilla API, allowing our consumers to easily communicate with our React component.

// ./scr/components/Connector.tsx
import { ReactComponent } from "./ReactComponent";
import { Root, createRoot } from 'react-dom/client';

export class ReactConnector {

    root:Root;

    constructor(targetEl:HTMLElement){
        this.root = createRoot(targetEl);
    }

    render(){
        this.root.render(<ReactComponent/>)
    }
}
Enter fullscreen mode Exit fullscreen mode

3.Render react component in vue

Now all we need to do is create an instance of the ReactConnector and pass the target element in which we want our React component to be rendered. Whenever the target element mounts on the DOM, we can render our React component inside it.
Importing TSX and JSX in Vue won't cause any errors because we are simply importing JavaScript; there's nothing wrong with that.

<script setup lang="ts">
// ./scr/components/VueComponent.vue
import { onMounted } from 'vue'
import { ReactConnector } from './Connector';

onMounted(()=>{
 const reactComponent = new ReactConnector(document.getElementById('reactContainer')!)
 reactComponent.render()
})
</script>

<template>
  <div id="reactContainer">
      <!-- render react component in here -->
  </div>
  <div class="card">
    <button type="button">vue button</button>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Now, if you run the app and check out the rendered VueComponent.vue, you can see that the React component is rendered inside it without any warnings or errors.
You can check out the final result in my GitHub repository:
github.com/amirkian007/react-vue-mix

Top comments (6)

Collapse
 
bcostaaa01 profile image
Bruno • Edited

Why would you want to render JSX in a Vue app? In my opinion, it has no real sense, because of the following points:

  • the idea of React is not rendering vanilla JavaScript code, but HTML in JavaScript, hence why it is called “JSX”, you’re not manipulating the DOM with vanilla JS. JSX is then translated into vanilla JavaScript on compile time.
  • secondly, even if you are working on a component library, it is unlikely that you would build a component for a React environment, and then translate it to other frameworks like Vue, because even though the core patterns look similar, the syntax and structure of the code are different. A feasible approach would be to first define the scope, design, and then build components for each framework. That’s why when you have different repos or directories in a component library for React, Vue, Svelte, Angular, and so on.
  • thirdly, rendering vanilla JavaScript in Vue is the opposite of the what the framework syntax was designed for: using template HTML to define components.

Yes, it is true, you can use JSX in Vue, but it makes absolutely no sense. It is like building a project with the two frameworks, why would you do it?

Collapse
 
amirkian007 profile image
Amir Adel

I disagree; it actually makes sense to use JSX syntax in a Vue app (not React, but the JSX syntax). Vue is a framework, which means the framework's template syntax is limited for advanced programmatic usage. If the component requires advanced template logic, then one approach would be to use JSX syntax for the template structure (again, just the syntax, not React). There is a plugin for that called "@vitejs/plugin-vue-jsx", and big projects like Vuetify are using it.

Rendering JSX has many methods, one of which is using the React library, which is not the best way. However, the purpose of this article is to demonstrate that method in a Vue app.

When working on a component library, one approach is to rewrite the project for every framework, but it is costly. Instead, it is more time and cost efficient to have a single core with a fast JavaScript library (like Preact or Solid.js) and a connector component for each framework (the connector component is in a separate repo). Check out fullcalendar.io, which is doing the exact same thing.

Collapse
 
blackr1234 profile image
blackr1234 • Edited

No React function component, no React hook, no mixed use of React and Vue components in parent-child relationship with props. This example is way too simple. I don't think this article is meaningful to anyone who wants to try it out in the real world.

Collapse
 
amirkian007 profile image
Amir Adel • Edited

I aimed to keep the article as simple as possible for everyone to understand. I plan to create a part two in a month (if I have the time), covering advanced real-world use cases like passing Vue reactive data as props to React components, utilizing Vue/React slots in React/Vue-based components, implementing Redux, and more.

I believe anyone interested in implementing these methods in a real-world project can figure it out. It's actually simpler than anticipated.

Collapse
 
blackr1234 profile image
blackr1234

Those are the essential (not "advanced") topics to cover for those who are interested in doing Vue+React in the same project.
Otherwise we won't know if mixing them really works and hence it will have no real world value.

I assume interested parties must be exploring if it is possible to let React developers and Vue developers work together on the same front-end npm project, build and mix different components using different SPA frameworks (or libraries).

Thread Thread
 
amirkian007 profile image
Amir Adel • Edited

By 'advanced,' I meant the coding part, not the topic. Because it might get complicated using Vue and React low-level APIs to make connector components.

As I said in the above comment, the only real-world use case is making a UI package with a core built with a fast framework/library like Solid.js and creating connectors for each framework/library, which has been done in some open source projects.

Mixing them will work but not the way you are thinking; they should be separated into different projects (or packages) and then connected. For example, in your Vue app, the sidebar can be a separate React package.

So why do this? What's a real-world actual use case? Here are some examples:

Example 1:
Suppose you (or your company) have multiple projects, each with a different framework and environment. You want to build a performant chat app on each project or a chart even. One approach would be to create a chat(orchart) package with a fast library like Solid.js and create Vue and React (maybe even Angular) connector components that can be used on all projects regardless of the app environment.

Example 2:
This is what I have actually seen implemented. Suppose you have an app that is using a very bad environment like jQuery mixed with PHP-blade environment, and the project is extremely big. Upgrading to a new modern environment takes one or two years, and the old one needs support and upgrades until the new version arrives. Like the first example, the best approach would be to build a package with a library and use it on both old and new projects. It saves a lot of time and money."