JSX HTML string variable displaying as text - javascript

I have a JSON file with a variable called htmlContent. I am trying to display this in a component but when it is rendered it shows it as text. I just want the text to be surrounded by an h2 tag.
MY JSON FILE
const BookData = {
data: [
{
id:"1",
pageHeader:"Contents",
htmlContent:`<h2>hello</h2>`,
definePrototypes:"",
exportComponent:"export default App;"
}
]
};
MY REACT COMPONENT
<section id='content'>
{props.htmlContent }
</section>
MY ACTUAL RESULT
<h2>hello</h2>
MY EXPECTED RESULT
hello

You need to use dangerouslySetInnerHTML to render html content in react, otherwise it will show as string
Change to be made in this element
<section id='content'>
{props.htmlContent }
</section>
Change the above block to
<section id='content' dangerouslySetInnerHTML={{ __html: props.htmlContent }}></section>
This should do the job. Check the link for details https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml

Try this
<div contentEditable='true' dangerouslySetInnerHTML={{ __html: props.htmlContent }}></div>
The immediate effect of using innerHTML versus dangerouslySetInnerHTML is identical -- the DOM node will update with the injected HTML.
However, behind the scenes when you use dangerouslySetInnerHTML it lets React know that the HTML inside of that component is not something it cares about.
Because React uses a virtual DOM, when it goes to compare the diff against the actual DOM, it can straight up bypass checking the children of that node because it knows the HTML is coming from another source. So there's performance gains.
More importantly- if you simply use innerHTML, React has no way to know the DOM node has been modified. The next time the render function is called, React will overwrite the content that was manually injected with what it thinks the correct state of that DOM node should be.
Your solution to use componentDidUpdate to always ensure the content is in sync I believe would work but there might be a flash during each render.
Reference Dangerously Set innerHTML

If React is imported in the JS file you can just remove the ticks(`) from the JSON like this:
const BookData = {
data: [
{
id:"1",
pageHeader:"Contents",
htmlContent:<h2>hello</h2>,
definePrototypes:"",
exportComponent:"export default App;"
}
]
};

Related

How to prevent styled-components from stripping custom HTML attributes?

My project is trying to switch to styled-components, but there is one big issue: our automated QA tests rely on a custom attribute called qa-component appearing in the dom for each HTML element that it is defined for.
The old way we did this worked fine: <div style={ styles.cssModuleStyle } qa-component="big-area" /> would translate to the dom as <div class="whatever" qa-component="big-area" />.
However, when using styled components, the qa-component attribute gets stripped because SC thinks its a prop.
How can I get styled-components to pass this custom attribute to the dom?
What you're looking for is withConfig + shouldForwardProp. It allows you to define what props get passed down. Here's how you can implement the desired behavior:
const StyledTitle = styled.h1.withConfig({
shouldForwardProp: (prop, defaultValidatorFn) =>
defaultValidatorFn(prop) || ['qa-attribute'].includes(prop),
})`
text-decoration: underline;
`;
Take a look at the docs here: https://styled-components.com/docs/api#shouldforwardprop
And here's a playground with this approach: https://stackblitz.com/edit/stackoverflow-71912300

DOM remove method in react js

I want to change remove a certain tag with an id in the html page, eg.<div id="theid"><p>sometext</p></div> Is there any ways to do it with react js? I know I can do it with javascript by document.getElementById("theid").remove();, how can I do it in the react way? I don't need a button or anything, just simply remove it when the page loads. I'd prefer methods without importing any modules or libraries if possible. Thank you.
You should likely use a ref:
https://reactjs.org/docs/refs-and-the-dom.html
So you attach the ref to the DOM element, then you can imperatively remove that element just like you specified.
So in the component function body:
const myRef = useRef();
Then in the component render:
<Component ref={myRef} />
Then you can use the code in your question to remove the element from the DOM.
ref.remove();
If you need to do it when the page loads look at using useEffect to achieve this. Although if you're removing an element on page load, I question why you even need the element there in the first place ;).
If it's rendered as part of React, the right way to do it would be to simply omit it from the source code:
const App = () => (
<div>
<div id="theid">foo</div>
<div>more content</div>
</div>
);
to
const App = () => (
<div>
<div>more content</div>
</div>
);
If it's not part of React, then remove it from whatever process generates the HTML.
If that's not an option - if it must be part of the HTML served to the client and it's not rendered as part of React - then you'll have to resort to doing what you're currently doing:
document.getElementById("theid").remove();
probably completely separate from your React script, since it's something you want to do only once, when the page loads, and not something that needs to be a part of the React lifecycles.

Change in HTML attribute of web component not reflected in Vue component

I'm facing the below problem.
I have a pure web component:
<my-web-comp options='["op1", "op2"]' active-option="op2"></my-web-comp>
This renders as two tabs with the second one selected by default. When you click on the other, the active-option HTML attribute changes to op1 and you can actually see that the property is changing in the DOM if you open the DevTools.
However, I cannot detect the change in the Vue component where I am using the web component. I have:
<template>
<div>
<my-web-comp :options="options" :active-option="activeOption"></my-web-comp>
</div>
</template>
<script>
export default {
name: 'MyVueComponent',
data() {
return {
options: '["op1", "op2"]',
activeOption: "op2"
}
},
computed: {
testVar() {
console.log("activeOption", this.activeOption) <--------- THIS LINE
},
}
}
</script>
The marked line only gets fired on the first load of the Vue component (printing "op2"). After that, testVar never gets modified again, doesn't mind if I click on the other tab and I don't see nothing in the console.
What can I be missing? I think it can be something related with Vue reactivity system, but can't wonder what.
This happens because your web-component mutates copy not a reference of this variable (copy created by your web component is also not reactive). There are two ways to change this:
You can modify your web component to use getters and setters to change value of this variable
You can use MutationObserver. To detect changes in your web-component. This approach will not require changes in this web-component
If you choose approach with MutationObserver then create this observer in vue mounted life-cycle-hook

Binding value as html in stenciljs

I am having trouble rendering a value with custom html inside into an element.
ex:
this.title = 'Hello <b> stencil </b>'; << response value from an API
Binding:
<h1>{this.title}</h1>
I am expecting something same as innerHtml behavior in JavaScript.
You can use
<h1 innerHTML={this.title} />
This is not a good practice in JSX, it is against the idea of virtual DOM and it's not creating virtual nodes.
You should try like this
this.salute = 'Hello';
this.name='stencil';
Binding
<h1>{this.salute} <b>{this.name}</b></h1>
Or if it is a more complex situation, build another smaller component.
However using innerHTML will work, but should be used in different situations more details here(at the bottom of the page).

React component ignores dynamic element while re-rendering

I have developed a react component with three div elements like below.
render: function(){
return (
<div id="div_1">
<div id="div_2"></div>
<div>
Click the below button
Click here
</div>
</div>
);
})
In runtime, using jquery am inserting few elements into "div_2" div like below.
componentDidMount: function(){
//Invoking global function, which is outside react
window.loadView();
}
And my load view method looks somthing like below,
function loadView(){
$('#div_2').html('//my elements')
}
Now to my surprise, when I change the status of my react component, the view is getting re-rendered but somehow the contents within "div_2" remains undisturbed. Can someone say why this behaviour?
React has its own virtual copy of the DOM, hidden somewhere. React uses this to do its magic in only updating DOM when something changed from state A to state B.
In your example, React is unaware of the changes you made with jQuery to <div 2>. So, as far a React knows, <div 2> is unchanged, so React does not update it.
I would strongly advise against mixing React and jQuery for updates to components. If you want to keep your code manageable, give React the exclusive monopoly to update the DOM.
In your case, I would advise to let React only manage the inner part, like so:
render: function(){
return (
<div>
Click the below button
Click here
</div>
);
})
And in your HTML:
<div id="div_1">
<div id="div_2"></div>
<div id="react-only domain"></div> // mount your ReactDOM here
</div>
You should use componentDidUpdate in your case instead of componentDidMount.

Categories

Resources