React mixing components and html inside root element - javascript

I want to pass server side data to React components without making async call.
I was wondering about building React app directly from my html page, something like what's written down here.
Is there a way to do something like this inside my html:
<body>
<div id="root">
<h1>Title</h1>
<ReactComponentA description="Lorem ipsum">
<div>
Test
</div>
...(maybe other react components or html here)
</ReactComponentA>
</div>
</body>
In other words I'm trying to mix html and react components inside react root element in my html view.
I hope I was clear
Thank you very much

React components aren't HTML and cannot be used in HTML page. JSX syntax is syntactic sugar for React.createComponent(...). Even though React.createComponent(...) could be used in HTML within <script>, it wouldn't make much sense there because React components should be rendered with ReactDOM.render any way in order to be useful, and this happens inside React application.
Another problem is that if ReactComponentA is defined inside React application, it wouldn't be available as ReactComponentA in global scope.
If an application is hydrated with data to avoid asynchronous AJAX calls, data can be provided with globals:
<script>
window.__APP_DATA__ = {/* provided in server-side template */};
</script>
And be used inside an application as window.__APP_DATA__.

Related

Visual builder to work with manually hard-coded templates/components

I wonder, is it possible to create a visual no-code builder to work with JS components (e.g. React JSX) if them are manually hard-coded before?
Let me explain what I mean.
Suppose a simple React component pages/index.js previously written by a developer manually:
function HomePage() {
return <div>Welcome to Next.js!</div>
}
export default HomePage
How can we change such a component in the front-end using a visual builder?
For example, we want to add a new HTML element (e.g. H1) inside the existing div.
As I can understand, the builder first needs to know in which JS file the HTML markup is stored to update it. So we can add id="homepage" to the div first and then store a relation as a config like
{"homepage": "pages/index.js"}
And now if we add a new element inside <div id="homepage">, the builder adds the element to the DOM of the div at the client, then takes the whole updated DOM of the div and writes back to the file index.js according to the config
Ok, but the file contains not only HTML markup - it's JS (React) code.
How to keep all the JS code e.g. function HomePage(), return, export default and so on ?
As an option, we can separately load all the JS code as HTML including non-HTML code as #text nodes. Then update the DOM and re-write everything back to the file.
But it sounds complicated and may cause unexpected issues.
So what solution would be the best?
Or maybe there is a ready React-specific solution?
Or maybe it's a bad idea at all to parse and re-write manually hard-coded components by visual builder and the only solution is to store everything as JSON like "homepage":{"div", {"class":""}, "Welcome..."} which is more easy for re-writing ? (but requires a new render)
It depends
I believe the answer that you are looking for very much depends on the level of flexibility that you want your no-code builder to have.
Depending on that, your project could benefit of the trade-offs and advantages of different solutions.
Let's briefly remember that basically a React component will need some props that then will be taken through a render template and output a working HTML. This is assuming a basic case where you don't need your react components to be smarter. Additionally, JSX is just sugar coating over function calls, so you could basically just compose functions to output a React component independently of using the JSX syntax. Hence no need to declare HTML, just changing the output of your no-code tool to JS instead of HTML.
For example, if you can modify how the no-code tool render, you can specify that when moving an element inside another you basically:
Highly Flexible & Customisable
In a highly flexible setup, I will recommend going through the last option you numbered, having a Data-Driven UI is the most common of the cases for complex systems. For example, Figma has an option to export the designs as react components, you can read how they do it here. Basically they take the tag output from figma which is a JSON of tags and create some React componets using templates. If you define "you own UI language" you could have quite a good control over what blocks you can build and define the way of interacting with them (e.g. adding a img component could be quite easy if you know the props and what it needs to render, then creating a React template for it is easy).
Limitations: you require to plan quite well the API of the parser and interaction between different sets of items.
Simple no-code builder
For simpler scenarios you could go with the first approach that you mention, you won't even need to add ids, some tools like React Developer Tools can already inspect the VirtualDOM to understand which part of the render belongs to which React Element (using react internals, which could take some time to understand, but for example you can inspect in the rendered how they use the data-reactid for identification). Knowing this, you can already define the template functions for the render() method (so the JSX output), and separate it code wise, so that when you generate the code, the HTML template is split from the React code as much as possible.
Silly example of how it could look:
// htmlBlockTemplate.js
export const helloPageTemplate = (props) =>
`<div> <h1>${props.title}</h1> </div>` // This can be generated from the `no-code`
// page.jsx
export const Page = (props) => {
return helloPageTemplate(props)
}
Using functions it could look like:
const Page = (props) =>
return React.createElement('div', null,
React.createElement('h1', title: prop.title, `The title ${title}`)
);
}
Limitations: eventho you could, adding custom components (like another React Component or a web component), it becomes more difficult since you will also have to deal with the import graph and probably.
Inevitably you will need to tweak how the render of the component works (rather by creating a parser from your UI language, or changing how the react component is written. If you have a good control of AST, then writing a parser for either of the cases should not be a problem.

Vue.js print raw html and call component methods

I am dynamically loading the html content from an ajax request. This html has some buttons like
<button #click="someComponentMethod">Add</button>
As you can see I am trying to call components methods. But Its not working.
I think instead of #click html's default attribute "onclick" should work. But this will only recognize the function that are defined in global scope. Can someone guide me how I can call component's function from core javascript i.e using "onclick".
Update
Ok! I got it that v-html will not compile that html. But can you guys tell me how can I call component method from javascript (i.e outside of component scope). In this way I will be able to use onclick="JAVASCRIPT_CODE_TO_EXECUTE_METHOD".
That content will not be compiled as mentioned in official docs :
The contents of the span will be replaced with the value of the rawHtml property, interpreted as plain HTML - data bindings are ignored. Note that you cannot use v-html to compose template partials, because Vue is not a string-based templating engine. Instead, components are preferred as the fundamental unit for UI reuse and composition.
Instead of loading html I end up saving component in JSON format. This component has a template property that stores the html string. In this way I am able to store and load component to and from database and it works without any issue.

Laravel and VueJS - where\how to put instance and components

I have a simple, probably silly doubt about this basic thing using Vue not for an SPA:
Considering that Vue in my project is used to make small pieces interactive (tables, lists), and general filtering of database records, should I create a Vue instance for every component and add <div id="app"> in the places I need those things
...
<body>
....
<div id="nav">...
....
<div id="app">
<component></component>
</div>
app.js
const table = new Vue...
const calendar = new Vue...
Or should I make a generic #app div right after the body tag, containing all the site and, inside that, inserting the single components to then manage everything in a single new Vue instance?
<body>
<div id="app">
<div id="nav>....
</div>
<div id="anotherDiv">
...
...
</div> <!-- #app div -->
</body>
app.js
const app = new Vue...
It is probably easier to have a generic #app in your root div that will contain all of your site. Then if you want to add more components, then all you have to do is create a vue component and register it. To register a new component to your Vue instance you can use the following code where you create a main.js file.
Vue.component('your-component-name', require('PATH TO YOUR COMPONENT'));
After your component is registered you can use it anywhere in the #app body.
There are many things to consider here and all answers will be somewhat subjective, so keep that in mind. I don't think that any single way is the "correct" way to do it. I have found that the simplest implementation is to have a single Vue instance in app.js, and then build your components and use them wherever you want in the app div. However, this can be overkill and may affect you negatively in a couple of ways.
As one example, if you are not 100% committed to using Vue, then it's most likely that you also want to use jQuery and maybe even some jQuery plugins somewhere else in your app. jQuery and Vue do not play very nicely together unless you are instantiating the jQuery within Vue components. For this reason, if you plan to utilize other javascript libraries such as jQuery, then you might consider using individual instances of Vue with smaller scopes wherever you need to use a component.
If, however, you use Vue to help with some global tasks, such as line-clamping or truncating, then you really are best served by having a global install.
As far as other considerations, such as overhead, I believe that either method would probably just about be even. When you load globally, you get the benefit of browser caching even though the script is on each page. When you load page-by-page, you get the benefit of not having to load the scripts everywhere and only using them as you need them. In either case, overhead is pretty minimal for Vue on the modern web, so I don't think this should play into your decision at all.
Those are my thoughts.
You can do like this:
// Imported components
import examplecomponent from './components/ExampleComponent.vue';
import adduser from './components/AddUser.vue';
and for call vue components in laravel view:
<div id="app">
<examplecomponent ></examplecomponent>
</div>
<script src="{{asset('js/app.js')}}"></script>
For more basic information:
Laravel and VueJS - where\how to put instance and components

AngularJS Directive into React App

We are looking at writing a new app using React but will need some existing Angular Directive that are specific for our business, for example a modified Angular Date Picker for example. There are many components so we won't be able to rewrite them all.
I am wondering if anyone has experience or knows the effort or feasibility of this?
The only article I've managed to find on this so far has been. Most resources I find mention going the other way from an Angular App with added React. http://softeng.oicr.on.ca/chang_wang/2017/04/17/Using-AngularJS-components-directives-in-React/
There's a library called angular2react that makes possible reuse angularjs code inside react components. You can see if it fits your needs. :)
I have written a simple demo app showcasing how to achieve it: react-angularjs-bridge
The basic steps are as follows:
Create a react component that is going to host the angular component in the DOM. This component should always render a simple html element (eg. a HTMLDivElement) so that react does not get confused when reconciling the virtual DOM with the real DOM.
After the react component was mounted componentDidMount, create a shadow root under the rendered HTMLDivElement and initialise the angular application under it. This will ensure that the angularJS component is encapsulated and is not affected by the react application and vice-versa
Click here for a demo. Check how the react application styles do not impact the styles of the angular component.
Independently of Angular, ref is a way to go: it gives to access to an underlying DOM node and the ability to manipulate the DOM inside that node in any way you like, including AngularJS. Your changes will stay - at least until react clears the component altogether.
You can create a ref in react by
<divOrAnyOtherDom ref={((el) => {this._elem=el;}).bind(this)}></...
(for the full description and alternate ways to the same end see here: https://reactjs.org/docs/refs-and-the-dom.html#callback-refs)
Anyway, as you now have a DOM node, you can start working with it, i.e. adding angular to the mix inside componentDidMount. Sadly, this is not really obvious - here's a way that has worked for me in the past (moduleName needs to be a module you have put in place already with your logic):
let baseElement = angular.element(this._elem);
let templateElement = angular.element(templateSource);
angular.injector([ 'ng', moduleName ]).invoke(function($compile, $rootScope) {
let cmp = $compile(templateElement);
scpe = $rootScope.$new(false);
scpe.varname = whateverYouHave; # point is: you can set scope variables
cmp(scpe);
baseElement.append(templateElement);
scpe.$digest();
});
Now you have angular inside the DOM node react gave you.
(I've taken this from a slightly different integration: Vaadin to AngularJS, but the principle is the same: Vaadin, just like react, gives you a DOM node. When you're interested in the full code: https://github.com/akquinet/vaangular/blob/master/vaangular/src/main/resources/de/akquinet/engineering/vaadin/vaangular/angular/NgTemplate.js)
Plus: For any callbacks from the angular component, you'll likely have to use setState et al.

variables, script tags inside a markup fetched from external source not rendered reactjs

React component is pulling HTML from external source. Few APIs are able to render the HTML part, but if we try to have a variable or script in that HTML, that is not working. Tried few things. Following is render method of component
render(){
const varInside = 'Some Variable Inside';
return (<div>
<script>console.log('Hello inside render');</script>
<div dangerouslySetInnerHTML={{__html: this.state.htmlContent}} />
<div>React HTML Parser - { ReactHtmlParser(this.state.htmlContent)}</div>
<div>React to HTML - { htmlToReactParser.parse(this.state.htmlContent)}</div>
<div>Raw content - { this.state.htmlContent }</div>
</div>)
}
htmlContent variable is pulled form external source using call, following is present in this variable.
<h2>This is a HTML fragment {varInside}</h2>
<script>console.log('Hello from fragment');</script>
The varInside is not getting replaced. Tried few options to convert HTML to react markup
API provided by react to set HTML
React HTML parser is using npm module react-html-parser
React to HTML is using npm module react-to-html
We get output something like
Also the script tag console.log is not getting called whether its inside render method or part of html coming from external source. If there a JS function which is part of markup, present in some other JS library, we were checking if that can get executed.
Having said that, why we are trying to do this (as this might not be right approach). We were evaluating a use case where HTML markup is fetched from a different CMS server and used in react components. There would be some pros and cons of trying to integrate reactjs with CMS (CMS work in traditional manner of every page being seperate page, while reactjs is a SPA based framework). But first we are first evaluating different options (exposing JSON instead of markup from CMS might be one option). Any suggestions would be helpful.

Categories

Resources