How to render html template with variables inside from in react? - reactjs

i am fetching html template from server.That template also have object data inside. I want to show that template in react component. I manage to show all the html elements with html-react-parser plugin, but my variables renders like string {data.title}.
const Template = ({templateData}) => {
const [data, setData] = useState({
title: 'Some title',
description: 'Some description'
})
return(
<Fragment>
{HtmlParser(templateData)}
</Fragment>
)
};
Compiles to:
<div>
<div class="title">{data.title}</div>
<div class="description">{data.description}</div>
</div>
Wanted result:
<div>
<div class="title">'Some title'</div>
<div class="description">'Some description'</div>
</div>
EDIT: found solution but it doesn't look like a good one :)
I replaced strings with variable.
HtmlParser(templateData
.replace(/{data.title}/g, data.title)
.replace(/{data.description}/g, data.description))

Related

Typescript React - use MouseEvents without passing it to child element

Can I use Mouse Events on whole React Element or I have to pass it to child element to get it work? After several functions components where I passed my handleEvent function I want to know if it's possible without getting a TypeScript error. My code is really simple
<Tile onHover={handleHover} name="Random name"/>
and Tile component
export const Tile: React.FC<{ name: string }> = ({ name }) => {
return (
<div className="tile-wrapper">
<h1 className="tile-header>
{name}
</h1>
</div>
)
}
What you want is to combine React.DOMAttributes<HTMLElement> with your custom props using an intersection. That will avail all the DOM events to your custom component, without having to manually pass it in.
export const Tile: React.FC<{ name: string } & React.DOMAttributes<HTMLElement>> = ({ name, ...events }) => {
return (
<div className="tile-wrapper" {...events}>
<h1 className="tile-header>
{name}
</h1>
</div>
)
}
As your Title component does not expect an onHover prop, it will just be ignored. The event you want to use is rather onMouseOver, which works on most HTML elements (according to documentation):
All HTML elements, EXCEPT: <base>, <bdo>, <br>, <head>, <html>, <iframe>, <meta>, <param>, <script>, <style>, and <title>
What you could do is the following, in the Title component:
export const Tile: React.FC<{ name: string, onHover: SomeType }> = ({ name, onHover }) => {
return (
<div className="tile-wrapper" onMouseOver={onHover}>
<h1 className="tile-header>
{name}
</h1>
</div>
)
}

React states are not being saved to the JavaScript array

I am learning about states in React, and below is an exercise to create a to-do list.
I capture the state of each inputted "item" in the to-do list and add them to an "items" array.
Then, each element in the "items" array is rendered using HTML.
I don't understand why I can't just push each item into a normal JavaScript array? After submitting the form, I log the "items" array. However, the "items" array only has 1 element, no matter how many times I submit the form. It seems like previous values are disappearing every time.
I solved the problem by using a React state that is an array. But I still don't understand why I can't use a JS array. Any explanations/resources would be greatly appreciated!
function App() {
const items = [];
//const [items, setItems] = React.useState([]);
const [inputText, setInputText] = React.useState("");
function handleSubmit(event) {
items.push(inputText);
console.log(items);
//setItems((prevValue) => {
// return [...prevValue, inputText];
//});
event.preventDefault();
}
function handleChange(event) {
setInputText(event.target.value);
}
return (
<div className="container">
<div className="heading">
<h1>To-Do List</h1>
</div>
<form className="form" onSubmit={handleSubmit}>
<input type="text" value={inputText} onChange={handleChange} />
<button type="submit">
<span>Add</span>
</button>
</form>
<div>
<ul>
{items.map((item) => {
return <li>{item}</li>;
})}
</ul>
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
You have to define the let items = []; outside the function. Because in react each component reloaded on state update. so it will re-assigned to empty array. Make sure you define it using let not const
You can use the react hook useCallback to prevent items re-rendering every time state changes const items = useCallback([], [])

Use a component inside a template literal

Inside of my render function I have another function that is used as a defaultProp. This function maps over an array and returns multiple divs that are basically ways to write HTML for a CMS.
Here is what that function returns:
const renderElements = elementsArray
.map(
item => `<div class="explanation"><h1>${item.title}</h1>
<h2>${item.code}</h2>
</div>
<CopyToClipboard text=${item.code}>
<button>Copy</button>
</CopyToClipboard>
<div class="example">
${item.example}
</div>
`,
)
.join('');
return `${renderElements}`;
};
However, I have the CopyToClipboard package that is imported. I've tried surrounding the component with ${}, but I can't get the CopyToClipboard to be used within this template.

How can I use useState Reactjs to control open or close a Modal Bootstrap? (not use ReactBootstrap library)

I am working with Bootstrap modal and Reactjs. Now I want to control how to open and close a Bootstrap Modal without Jquery code. So my idea is using useState to control state of modal, if true it will add class "show" to open modal and false it add class "hide". But it not work, How can I solve this? Or are there anyway to control modal without Jquery code? Thanks
const [openModal, setopenModal] = useState(false);
const openmodal = () => {
setopenModal(!openModal);
};
return (
<div>
<button onClick={openmodal}>open</button>
<div id="mod" className={`modal ${openModal ? 'show' : 'hide'}`}>
<div className="modal-dialog modal-xl">
<div className="modal-content">
hello
</div>
</div>
</div>
</div>
You could use the data attributes.
Options can be passed via data attributes or JavaScript. For data
attributes, append the option name to data-, as in data-show="".
The data-show attribute specifies whether to show the modal when initialized.
<div id="mod" data-show={openModal ? 'true' : 'false'}> ... </div>
See: https://www.w3schools.com/Bootstrap/bootstrap_ref_js_modal.asp
Alternatively you could use useRef to get the modal DOM element and access it.
function model(){
const [openModal, setopenModal] = useState(false);
const openmodal = () => {
setopenModal(state=>!state);
};
return (
<div>
<button onClick={openmodal}>open</button>
<div id="mod" className={`modal ${openModal ? 'show' : 'hide'}`}>
<div className="modal-dialog modal-xl">
<div className="modal-content">
hello
</div>
</div>
</div>
</div>
)
}

React returns image src as object

I have a variable defined like this:
const team = [
{
name: "Foo",
bio: "FooBar",
image: { foo }
},
{
name: "Bar",
bio: "FooBar",
image: { bar }
},
];
Where the images are imported like this:
import foo from "../assets/foo.jpg";
import bar from "../assets/bar.jpg";
These are then passed to a component to be rendered, with:
<TeamRow team={team} />
The TeamRow component looks like this:
const TeamRow = props => {
const items = props.team.map((item, index) => {
return (
<div className="col-10 col-sm-4 col-md-1 mx-auto text-center">
<div className="row">
<div className="col-12 teamMemberImage">
<img className="img-fluid" src={item.image} />
</div>
</div>
<div className="row">
<div className="col-12">{item.name}</div>
</div>
<div className="row">
<div className="col-12">{item.bio}</div>
</div>
</div>
);
});
return <div className="row">{items}</div>;
};
export default TeamRow;
The images fail to render. When I look at them in the dev tools, they have src="Object object". The class that calls TeamRow, is the class in which team is defined. After defining it, calling console.log(foo returns the url pointing to the image, as expected. Somehow, in being passed to the second component, the expected behaviour ceases.
Strangely, earlier, I was using the react logo as a placeholder. So:
import logo from "../assets/logo.svg";, and this worked, but only if I rendered it as src={item.image.logo}.
{ foo } is shorthand for { foo: foo }, and { bar } is shorthand for { bar: bar }.
Instead of putting the image url in an object with a key that will be different for every image, you can set it as the image property directly.
const team = [
{
name: "Foo",
bio: "FooBar",
image: foo
},
{
name: "Bar",
bio: "FooBar",
image: bar
},
];
team[0].image is an object on the form {"foo":"yourUrl"} because you've wrapped foo in brackets, which uses the object shorthand syntax to create a property named foo with the value in variable foo. Remove the brackets around foo and bar
You don't need to put your image files alias names inside the {foo}, you can just write image: foo otherwise it will return as [object object].
In my case, I was struggling for the last four hours. but, it was a Next JS project so I need to put the image properties in an image component.
<Image src={props.img} /> instead of <img>

Resources