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
-
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
-
Install
react
and andreact-dom
as dependencies :
npm i react react-dom
-
Install
@vitejs/plugin-react
as devDependencies :
npm install @vitejs/plugin-react --save-dev
-
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()], })
-
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>
)
}
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/>)
}
}
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>
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 (7)
Why would you want to render JSX in a Vue app? In my opinion, it has no real sense, because of the following points:
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?
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.
it's about component reuse or maybe importing an existing react library
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.
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.
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).
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."