Motivation
I have an ASPNET CORE MVC + jQuery application and I need to gradually migrate some components to React!
Since we already have the data from the ViewModel, I would like to pass it to the React component.
Proposal
Why not use data attributes?
I created a data attribute structure that can be read in React and invoke my components (Lazy) with their properties.
That way, I don't need to write javascript code every time to bind 'react' to html.
Requisites
- Webpack
- Webpack chunk
- React
My structure of data-attributes
<div data-js-component="FavoriteButton"
data-js-props='{
"favorite": @Model.Document.Favorite.ToString().ToLower()
}'>
</div>
- data-js-component: string (name of component to scan and invoke)
- data-js-props: json (all properties of initial state)
My React Component
import React from 'react';
export default function FavoriteButton({ favorite }) {
...
...
}
My InvokeComponents:
How to Works
First, register your components with their respective path to lazy import on 'components' object.
It will be searched for [data-js-component] in the html. When the element is found, it will be read from the 'components' object.
The [data-js-props] will be cast to json and pass to React Component found.
import { lazy, Suspense } from 'react';
import ReactDOM from 'react-dom';
const InvokeComponents = (function() {
//register here your components
const components = {
DocumentFavoriteButton: lazy(() => import('./Documents/DocumentFavoriteButton')),
FavoriteButton: lazy(() => import('./FavoriteButton'))
}
const elements = document.querySelectorAll('[data-js-component]');
for (const element of elements) {
const { jsComponent, jsProps } = element.dataset;
const ComponentFound = components[jsComponent];
let props = JSON.parse(jsProps);
ReactDOM.render(
<Suspense fallback={<p>...</p>}>
<ComponentFound {...props} />
</Suspense>,
element
);
}
})();
export default InvokeComponents;
Now, register your InvokeComponent on _layout cshtml page:
<script src="/dist/Components/InvokeComponents.js" asp-append-version="true"></script>
And finishing, modify your webpack.config like this to support chunk used on lazy.
output: {
path: path.resolve(__dirname, 'wwwroot'),
publicPath: '/',
chunkFilename: '[hash].[name].js',
filename: '[name]'
},
Top comments (2)
Instead of using React take a look at Preact + Preact Habitat. It is a really nice combination to achieve what you are trying to do. You will end up with simple widgets you can invoke and have a very small size because of Preact. Later, if you really need, you can easily replace Preact with React and get rid of Preact-habitat.
Very cool approach. Thanks for sharing.