The One with Vue in React

Anish Kumar
Technology at upGrad
4 min readDec 30, 2019

--

Why would you do that?

That was the first reply I got when I mentioned this in the React community. Well, can’t blame them, you might be wondering the same.

I will tell you why

The Vue widget here was a tagging plugin, that we have to integrate across different platforms with tech stacks including Backbone.js and React.js.

Now you might ask:

Why didn’t you build it in React then?

We went for Vue because it provided a much easier and faster development pace and not to mention a much smaller build size. By now the React devs are frowning and grinding their teeth. I know comparing frameworks and libraries can be a controversial topic.

Just for the record, I am a React fan

Don’t kill me

So let's continue the story

My task was to integrate the tagging plugin into 5 types of forms in the test platform which is currently under development ⚒. The platform provides 5 types (Multiple Correct, Single Correct, Numerical, Coding, and Open Text questions) of question creation forms.

The first thing was obviously to make a separate Tagging Component in React, which will handle all the integration logic of the Vue widget.

Let's move to the integration

Like every other developer, my first instinct was to google whether someone has done this before. I was confident enough that there will be someone who has faced the same problem. Unfortunately, I wasn’t able to find any example. Whaaaat?!!! That's the main reason I am writing this blog.

What now?

I knew the only place where I can get help is the Vue docs. To my luck, the Vue documentation was as clear as the frame on Monica’s door. For all those muggles out there (the ones who aren’t crazy fans of F.R.I.E.N.D.S), this just means crystal-clear.

To begin with, what I needed was a way to create an instance of a Vue app and mount it on a div in the React tagging plugin component. By the way, React doesn’t render a Vue widget if you directly use it in the render HTML like this 👇

function TaggingPlugin(){
//react tagging plugin component
...return <vue-tagging-plugin/> // vue tagging component
}

So I had to create the Vue instance programmatically, like this 👇

Not to worry, I am gonna explain this in detail

var vm = new Vue({   // options })

This creates a Vue app instance and mounts it on the el which is the root HTML node.

We have a Vue instance created and the node to be mounted on. What we need now is the widget we need to render in the Vue app, which brings us to the very important part 👇

render: function(h) { // h = createElement     return h(window.taggingPlugin, {        props: this.props     });}

The render API of Vue is passed a createElement function. This creates the HTML, hydrates it with the data & props if any and finally returns a Vue node which is then appended to the DOM. The first argument to createElement can be an HTML tag name, component option or any async function that resolves (which in our case is the instance we created) to any of the above. The second argument is an object with attributes that you use in a normal Vue component definition, in my case, the props for the widget.

Now we have is the data prop 👇

data() {     
return {
...
props: {
}
}
}

The data prop in Vue is basically the equivalent of React component’s state. Now you might be wondering why did I create a props object in the data and use that props, in turn, to pass it to the Vue createElement’s prop. So the reason is that the widget I created is a child of the root Vue Instance and it was also a better way to pass down the data from the root of the app itself, instead of directly injecting the props from React component.

return h(window.taggingPlugin, {          
props: this.props
});

The this here is the Vue instance, so we can easily access the data of the Vue app. So whenever I needed to update the id prop in the Vue widget from React component, I would do something like this 👇

useEffect(() => {     window.taggingInstance.props.config.componentId = id;}, [id]);

Well the part where everything comes together 👇

This is the React component after all the integration with Vue widget.

Also, JFYI, for the taggingPlugin to be available in the window you have to add the widget build js file, CSS file and Vue bundle files in your index.html of the React app.

Conclusion

Not finding any solution when I googled this for the first time was a turning point. Otherwise, I wouldn’t have gone through the amazing Vue docs and got a deeper understanding of Vue internals - how a component is rendered, how the data flow works, and most of all, the rush of finding a way out to solve such an interesting problem. I am sure that there will be better and efficient ways of doing this. If there are any such references or methods please do add them in the comments.

--

--