Render HTML DOM Node in React Component - javascript

I am using Wordpress as my CMS and creating some of the pages in React and rendering it. I have a use case where i need to render HTML DOM Node inside of my React Component. I am getting the DOM Node with the help of querySelector() which returns me the DOM node. In React i am trying to render it using React.createElement. But it renders as [object HTMLDivElement] on my page.
render() {
const { reactPages } = this.props;
const innerPages = React.createElement('div', {id: "myDiv"}, `${reactPages.children[0]}`);
return (
<div className="react-cmp-container">
<h3>React Container</h3>
{ innerPages }
</div>
)
}
}
The other thing i tried was using the dangerouslySetInnerHTML:
rawMarkUp = () => {
const { reactPages } = this.props;
return {__html: reactPages}
}
render() {
const innerPages = React.createElement('div', {id: "myDiv"}, )
return (
<div className="react-cmp-particle-container">
<h3>React Particle Container</h3>
<div dangerouslySetInnerHTML={this.rawMarkUp()}></div>
</div>
)
}
This is the type of DOM Node that i am getting and passing it as props to my Component.

This is not recommended to to. It might cause many kinds of trouble later. Anyway, ...
querySelector() returns a DOM-element (or collection of such).
1. React.createElement
React.createElement does not work, because it expects another React.Element, or a string, not a DOM-element.
2. dangerouslySetInnerHTML
dangerouslySetInnerHTML does not work, because it expects a HTML string, not a DOM-element.
You could use domElement.innerHTML and put the HTML string into dangerouslySetInnerHTML, but that might not represent the DOM element as you want it.
3. useRef
You could add a ref to some element that is rendered by React. This gives you access to the corresponding DOM-element (rendered by React), and you can inject your DOM-element (returned by querySelector()) using normal DOM methods.
This disables React to "track what's going on", and you might experience inconsistent state and hard-to-understand bugs.
e.g.:
export const StaticHtml = (props)=>{
const ref = useRef();
useEffect(() =>{
var elm = document.getElementById('some-static-html');
ref.current.appendChild(elm);
}, []);
return (<div ref={ ref }>
some div
</div>);
};

Related

How to wrap JS library which creates elements by itself into Vue component with slot?

I have vanilla JS library which is given root element and callback function (data: any) => HTMLElement. Library calls callback and positions elements within root one.
I want to wrap this library into Vue component with slot to use it like this:
<my-component v-slot='data'>
<div>{{data.field}}</div>
</my-component>
Slots returned by useSlots are functions which, being called, return virtual DOM. How can I turn this into real DOM element retaining reactivity?
Seems to work this way:
const component = defineComponent({
props: ['data', 'render'],
render: function() {
return this.render(this.data)
},
})
function callback(data: any): Element {
const elem = document.createElement('div')
const app = createApp(component, {render: slots.default!, data})
app.mount(elem);
return elem
}

Alternative for document.querySelector in react js

I've red many articles about using useRef in react js. According to react js documentation, Refs provide a way to access DOM nodes or React elements created in the render method..
From all of documentation, i understood that, if you want to access a dom element, you have to add the ref like this:
<div ref={myRef}, and after that easy to access it.
I understood that useRef is used when we have access to the html markup.
Question: How to access a css selector (.class, #id), when my html is generated by a library, like
AntD or something else?
How to access this selector if i can't use document.querySelector according to react documentation? EX:
document.querySelector('my selector').style.color = 'yellow';
Which is the alternative for the last code snippet in react js?
NOTE: I don't want to change the styles with css, but i need to change it according to some js logic.
You can use querySelector and querySelectorAll in situations where the DOM structure you're accessing is generated outside of React. That's absolutely fine when you have no other choice.
You'd probably use them on the outermost element of your component or the element in which you're having the non-React library do its thing (which you'd get via a ref), rather than on document, so that they're working just within your component's part of the DOM rather than the entire document.
Here's an example:
"use strict";
const { useState, useEffect, useRef } = React;
// A stand-in for your non-React library
function nonReactLibraryFunction(element, value) {
element.innerHTML =
`<div>
This is content from the non-React lib, value =
<span class="value">${value}</span>
</div>`;
}
// A stand-in for your component
const Example = ({value}) => {
// The ref for the wrapper around the lib's stuff
const fooRef = useRef(null);
// When `value` changes, have the library do something (this
// is just an example)
useEffect(() => {
// Valid target?
if (fooRef.current) {
// Yes, let the lib do its thing
nonReactLibraryFunction(fooRef.current, value);
// Find the element we want to change and change it
const color = value % 2 === 0 ? "blue" : "red";
fooRef.current.querySelector(".value").style.color = color;
}
}, [value]);
return (
<div>
This is my component, value = {value}.
<div ref={fooRef} />
</div>
);
};
// A wrapper app that just counts upward
const App = () => {
const [value, setValue] = useState(0);
useEffect(() => {
setTimeout(() => setValue(v => v + 1), 800);
}, [value]);
return <Example value={value} />;
};
ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.development.js"></script>
If you use external libraries that generate their own markup. Nothing bad to use element.querySelector
You can do something like this:
React.useEffect(() => {
const element = document.querySelector(selector);
}, []);
But if you use a library from React's ecosystem like Antd or material-ui, they probably have an API with refs. It can be called like innerRef, nestedRef or just ref
In addition to previous anwsers: if this generated html is generated inside your component you can use querySelector on useRef.current to search for element only inside component ;)
const Component = () => {
const componentRef = useRef(null);
useEffect(() => {
const elFromLibraryComponent = componentRef.current.querySelector('my selector');
if (elFromLibraryComponent) {
...do something...
}
}, [])
return (
<div ref={componentRef}>
<ComponentFromLibrary />
</div>
)
}
There are even libraries that allows to pass ref as prop to components so it is also usefull
If you are using multiple external resources to generate markup. Try this:
useEffect(() => {
const element = window.parent.document.querySelector(selector);
},[]);
We can also manipulate HTML Dom element by tags,id,class with the help of document.getElementsByTag('TagName').Document.getElementById('IdName'),Document.getElementsByClass('ClassName').

How to get a reference to the created DOM from a templateResult (not using custom elements)

For those crazy folks like me that wouldn't want for various reasons to use custom elements, is there a way to access the DOM related to a templateResult?
I tried to modify the templateResult's content before rendering but without success... I also looked into templateFactory, but it seems it's desinged for the ultimate (parent) templateResult rendered to a container, not nested templateResults.
const componentA = {
id: 'comp-a',
template(){ return html`<div>No ID yet</div>` }
};
const app = {
template(){
const tmpl = html`<main><div>${ componentA.template() }</div></main>`
// here: use componentA.id to set top element's id
// seems it's too late to change the template, DOM is already created?
// so how to get a reference to the created DOM from a templateResult?
return tmpl
}
};
render( app.template(), document.body);
For example, how could I automatically set an id on the top element of componentA from its id?
The thing is lit-html actually creates TemplateResults which are just representations of the HTML that will be created once render() is called.
In this sense the <div> inside A's template has no particular "meaning" with respect to the TemplateResult representing it, but its instances can still be normally querySelected from the render container.
const tmpl = html`
<main>
<div>
${componentA.template()} <!-- This returns a TemplateResult -->
</div>
</main>
`;
You're still totally allowed to assign an id to the <div>:
const componentA = {
// ...
template() {
return html`
<div id="comp-a"></div>
`;
}
}
If you want to assign the id only at a later stage, you can pass it as argument to the function that creates A's template:
const componentA = {
// ...
template(id) {
return html`
<div id=${id}></div>
`;
}
}

How can I render object HTMLDivElement in my react component?

I have this code(its part from a bigger class but the relevant parts are here)
what I try to do is to take an existing div('#qr') that has a QR code that we got from Third Party and make some changes if needed after some checks.
I got this error:
invariant.js:42 Uncaught (in promise) Error: Objects are not valid as a React child (found: [object HTMLDivElement]). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of...
I'm looking for a way to render object HTMLDivElement in my react class.
the relevant code looks like this:
getQrCode() {
const qrCodeElem = document.querySelector('#qr');
const uri = encodeURI('some specific url');
if (qrCodeElem && qrCodeElem.childNodes.length === 0) {
return new QRCode(qrCodeElem, {
text: uri
});
}
return qrCodeElem;
}
render() {
return (
<div>
<div id="qr"></div>
{this.getQrCode()}
</div>
);
}
We can not insert DOM elements directly , you can use ref attribute to get reference to the parent element and insert your node after componentDidMount
getQrCode() {
const qrCodeElem = document.querySelector('#qr');
const uri = encodeURI('some specific url');
if (qrCodeElem && qrCodeElem.childNodes.length === 0) {
return new QRCode(qrCodeElem, {
text: uri
});
}
return qrCodeElem;
}
componentDidMount () {
this.qrCodeContainer.appendChild(this.getQrCode());
}
render() {
return (
<div ref={node => this.qrCodeContainer = node}>
<div id="qr"></div>
</div>
);
}
Your function is returning multiple dom nodes. Wrap them with additional tag (div, span, ...) or use fragments:
<>{this.getQrCode()}</>

What are appropriate return types for a ReactJS Component.render() function?

The React Tutorial has a render apparently returning an array of rendered nodes:
// tutorial10.js
var CommentList = React.createClass({
render: function() {
var commentNodes = this.props.data.map(function (comment) {
return (
<Comment author={comment.author}>
{comment.text}
</Comment>
);
});
return (
<div className="commentList">
{commentNodes}
</div>
);
}
});
What are acceptable return types for a render() method for a component? An array seems to work? What about an array of arrays? If I have data stored in an array of arrays of codes, how do I appropriately render the grid?
You must always return a react component, but the contents of that component (as long as they are valid jsx syntax) can be an array, an array of arrays containing react components. E.g.
var MyComponent = React.createClass({
render: function () {
var single = <p>Single</p>;
var array = [
<p>One</p>,
[<p>Two</p>],
[<p>Three</p>]
];
return (
<div>
{single}
{array}
</div>
);
}
});
React.render(<MyComponent />, document.body);
jsbin
Typically you would take the data, iterate over it (however many levels deep) and generate your components. Array.Map and other "functional" helpers are particularly helpful in situations like this.
If you check the docs you'll see that you can only return a component or null/false from render.
"The render() method is required. When called, it should examine this.props and this.state and return a
single child component. This child component can be either a virtual
representation of a native DOM component (such as or
React.DOM.div()) or another composite component that you've defined
yourself.
You can also return null or false to indicate that you don't want
anything rendered. Behind the scenes, React renders a tag
to work with our current diffing algorithm. When returning null or
false, this.getDOMNode() will return null."
http://facebook.github.io/react/docs/component-specs.html

Categories