Load specific DIV with a react component without reloading the whole page - node.js

I have a menu where every menu item is a button and I want to load a specific reactjs component into a specific div without reloading the whole page.
This is the current code, clearly is bad but I don't know where to start fixing it...
...
<Button onClick={this.loadTarget}>
{menuItem.name}
</Button>
...
loadTarget(event) {
document.getElementById("datapanel").innerHTML="abc<TranslationsList />";
}
When I click a menu Item I want to load my div with the value "abc<TranslationsList />". "abc" is displayed but the custom component "TranslationsList" is not and I guess this is normal as the TranslationsList tag is not a HTML tag. But how could I load my component?
I could use links instead of buttons but in this case the question is how could I update the div content with a specific link?

It's hard if you've programmed plain JS before, but you have to forget the "good old JS pattern" in React. I also had a hard time getting used to not using standard JS elements (target, innerHTML, etc.) to solve such a problem.
So the solution in React is to use the framework and your page reload problem will be solved immediately. useState for the state of the component and handlers for the click. My main code looks like this. You can find a working application at Codesandbox.
export default function App() {
const [showComponent, setShowComponent] = useState(false);
const handleButtonClick = (e) => {
setShowComponent(!showComponent);
};
return (
<div className="App">
<h1>
Load specific DIV with a react component without reloading the whole
page
</h1>
<a href="https://stackoverflow.com/questions/74654088/load-specific-div-with-a-react-component-without-reloading-the-whole-page">
Link to Stackoverflow
</a>
<div style={{ marginTop: "20px" }}>
<button onClick={handleButtonClick}>Magic</button>
</div>
{showComponent ? (
<div style={{ marginTop: "20px" }}>
This is the place of your component!
</div>
) : (
""
)}
</div>
);
}

In the first place I wpuld not use vanilla JS syntax on a react app if it is not necessary. i.e: document.getElementById("datapanel").innerHTML="abc<TranslationsList />".
If you are using React you should be managing the State in the component of the DIV, giving the order to make an element appear once the button is clicked.
A simple example can be this:
CodeSandbox
import { useState } from "react";
export default function App() {
const [divState, setDivState] = useState(null);
const divElement = () => <div>I am the element that should appear</div>;
const handleDiv = () => {
setDivState(divElement);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={handleDiv}>Show DIV</button>
<div>{divState}</div>
</div>
);
}

I agree with the answers given above. Since you are already using React, you should take advantage of its features/functionalities. No need to reinvent the wheel.
However, if you are still interested in how to make your current implementation work. You may use renderToString(), which can be imported from ReactDOMServer. Please refer to the following code snippet as an example.
import { renderToString } from 'react-dom/server'
const TranslationsList = () => {
return <div>TranslationsList Content</div>
}
export default function App() {
const loadTarget = () => {
document.getElementById("datapanel").innerHTML=`abc${renderToString(<TranslationsList />)}`;
}
return (
<div>
<button onClick={loadTarget}>Insert Component</button>
<div id="datapanel">Data Panel Holder</div>
</div>
);
}

Related

How to change the text and path of a navigation button?

I have a navbar component, which has a button that transforming me to path (React-Router) "/NEXUM", But, When I'm transformed to NEXUM, i want to change the text of the navbar and the navigation path, so when I click it, it will bring me to a different path, called "/".
const NavBar = () => {
const navigate = useNavigate()
const homeToNavigate = () => {
navigate('/')
}
const Navigation = () => {
navigate('/nexum')
}
return (
<Box sx={{ flexGrow: 1 }}>
<AppBar id="bar">
<Toolbar>
<img onClick={homeToNavigate} className="logo" src={logo}></img>
<Button onClick={Navigation} id='nexumNavigation'> להכנסת קובץ אקסל ישיר </Button>
</Toolbar>
</AppBar>
</Box>
)
}
export default NavBar
This is The nav bar component, The "navBar" component is used in both "HomePage" Component that I'm using and "SpagetiComponent", So as I said, I need the purpose of the button to change, I tried doing it with props, but I was unsuccessful, if you have an idea, please let me know.
let location = useLocation();
<Button onClick={location.pathName==="/NEXUM"?homeToNavigate:Navigation} id='nexumNavigation'>{location.pathName==="/NEXUM"?"go home":"go NEXUM"} </Button>

How can I fix these console.log errors after using iframe embed google map in reactjs component?

iframe used in react component:
import React from 'react';
const StoreMapLocation = () => {
return (
<div>
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d14387.771831185173!2d102.77328521573708!3d25.640018633937373!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x36da58403c9938ef%3A0x2ad1b6679ae45280!2sJijiexiang%2C%20Xundian%20Hui%20and%20Yi%20Autonomous%20County%2C%20Kunming%2C%20Yunnan%2C%20%E0%A6%9A%E0%A7%80%E0%A6%A8%2C%20655213!5e0!3m2!1sbn!2sbd!4v1651750063366!5m2!1sbn!2sbd"
className="h-96 w-full border-2 rounded-lg shadow-lg" allowFullScreen="" loading="lazy"></iframe>
</div>
);
};
export default StoreMapLocation;
console log error:
google.maps.event.addDomListener() is deprecated, use the standard addEventListener() method instead: https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener
The feature will continue to work and there is no plan to decommission it.

Can you use templates in Next.js?

I am fairly new to web development and currently have a rudimentary web server using Node.js, Express, and Pug which I am hoping to convert to Next.js. Is it possible to create re-usable templates (similar to Pug/Jade) in Next.js?
This is how I do mine. There are better ways, but it's how I like it. I came from express handlebars, and have used pug before, so this is how I did mine.
In pages/_app.js file:
import React from 'react'
import Head from 'next/head'
export default function MyApp({ Component, pageProps }) {
const Layout = Component.Layout || LayoutEmpty // if page has no layout, it uses blank layout
const PageTitle = Component.PageTitle // page title of the page
return (
<Layout>
{PageTitle? (<Head><title>{PageTitle}</title></Head>) : '' }
<Component {...pageProps} />
</Layout>
)
}
const LayoutEmpty = ({children}) => <>{children}</> // blank layout if doesnt detect any layout
In your component folder where ever you want to put your layout file: eg component/layout.js
import Link from 'next/link';
import {useRouter} from 'next/router'
export function LayoutOne({children}) {
try {
return (<>
<nav>
<ul>
<li><Link href="/"><a>Home</a></Link></li>
</ul>
</nav>
<div>{children}</div>
</>)
} catch(e) {console.log(e)}
}
Then in your pages: eg pages/about.js
import React, { useState, useEffect } from 'react';
import {LayoutOne} from '../component/layout' // location of your layout.js file
Aboutpage.PageTitle = 'About | Website Tag Line' // set title of your page
Aboutpage.Layout = LayoutOne // using LayoutOne. If you dont do this, its considered blank layout and you'll get no layout
export default function Aboutpage() {
try {
return (
<>
<div>
<h2>About</h2>
</div>
</>
);
} catch(e) {console.log(e)}
}
If you want more layout, in your layout.js file at the end, just change the name of the export function eg: LayoutTwo
export function LayoutTwo({children}) {
try {
return (<>
<nav>
<ul>
<li><Link href="/dashboard"><a>Dashboard</a></Link></li>
</ul>
</nav>
<div>{children}</div>
</>)
} catch(e) {console.log(e)}
}
And one the page, you change layout to two
import {LayoutTwo} from '../component/layout'
Aboutpage.Layout = LayoutTwo

How do I create show page based on id of item clicked

I am creating list of items looped through .map function. I want each of these items be rendered in a single page with some other details.
import React from 'react'
import {faArrowRight, faMusic, faPlay, faPlayCircle, faTachometerAlt} from "#fortawesome/free-solid-svg-icons";
import {FontAwesomeIcon} from "#fortawesome/react-fontawesome";
import music from '../mocks/music.json'
import { Link } from 'gatsby'
import Music from '../pages/music'
const newData = music.map( (data) => {
return (
<div className="row no-gutters justify-content-between align-items-center">
<div className="col-auto">
<button className="btn-gradient btn-circle">
<FontAwesomeIcon icon={faPlayCircle} />
</button>
</div>
<div className="col">
<div className="music-list-content">
<span className="artist">{data.author}</span>
<Link to={`/music/${data.id}`}>{data.title}</Link>
<span className="play">
<FontAwesomeIcon icon={faPlay} /> {data.duration}
</span>
</div>
</div>
<div className="col-auto">
<span className="badge-dark badge">{data.genre}</span>
</div>
</div>
)
})
const membersToRender = music.filter(member => member.id)
const numRows = membersToRender.length
const Musics = () => {
return (
<div>
<div className="title">
<h5>New Music</h5>
<span>{numRows} new songs</span>
</div>
<div>
<div className="music-list card-wrapper">
{newData}
</div>
</div>
<div className="footer-wrapper">
<div>
<FontAwesomeIcon icon={faMusic} />
<span>Song Library</span>
</div>
<FontAwesomeIcon icon={faArrowRight} />
</div>
</div>
)
}
export default Musics
I created a link which whenever I click, it takes me to another page (page not found) with id appended and .js extension.
Please, how do go about it? I want a click on the title and have it displayed on a full page.
Your logic seems good, however, you are missing the most important part, the page creation, since you are not creating the pages, all of your links are broken.
In Gatsby, you have two different ways of creating pages:
Using gatsby-node.js to create pages dynamically: when dealing with a huge amount of data, like your JSON, it's easier to let Gatsby deal with this responsibility of creating pages for Gatsby. Since you are sourcing from a JSON, you need everything set to create dynamic pages.
const path = require("path")
// Implement the Gatsby API “createPages”. This is called once the
// data layer is bootstrapped to let plugins create pages from data.
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const musics= require("./data/mocks/musics.json")
const musicTemplate = path.resolve(`src/templates/music-template.js`)
musics.forEach(music) => {
createPage({
path: `/music/${music.slug}`
component: musicTemplate,
context: {
title: music.title,
description: music.description,
// and so on for the rest of the fields
},
})
})
}
Note: I'm assuming that your JSON is properly defined and formatted, having all the fields I queried.
Your musicTemplate must be a template (inside /templates folder).
Notice that you are passing some fields through Gatsby's context, this means that those fields will be available through props.pageContext in your template. So, there, create a template like:
import React from "react"
import Layout from "../components/layout"
export default function MusicTemplate({pageContext}) {
return (
<Layout>
<div>Hello musician {pageContext.title}</div>
</Layout>
)
}
So, as I said, with this approach you are creating dynamic pages based on your JSON file, and they will be available inside localhost:8000/music/{music.slug}, and all your reference and links that point there, will be valid.
I would also recommend using static query/useStaticQuery to retrieve data from your JSON in that loop. If you create a static query from that data (in a separate component) you will be able to fetch it on-demand across your project, so you will be reusing an interesting part of logic. It's better to use it rather than requesting a JSON directly.
You can follow this guide from the great Jason Lengstorf which is mostly what you need.
Adding .js files in your /pages folder: Gatsby infers the internal structure of your /pages folder and will create pages accordingly to that structure. For instance, if you have a structure like: /pages/musicians/name1.js Gatsby will create a page like localhost:8000/musicians/name1.
As it has been said, the first approach fits your requirements and it's preferred for this use-cases, since the second one will be less scalable and maintainable.
You should do some routing with React-Router (https://reactrouter.com/web/example/basic).
So the link have to point to a Route in a Switch, as is in the example of the link.

View collections item in Mern

I have some items in a mongodb collection, now i want to view them on a react app, i've that code, but it doesn't display nothing, but if i check value with a console.log() i get the content. How i can do?
import axios from "axios";
const viewMails = []
axios.get('http://localhost:5000/emails').then(res => {
let emailString = JSON.parse(res.request.response)
for (const [index, value] of Array(emailString).entries()) {
viewMails.push(
<div key={index}>
<h1>{value.name}</h1>
<h3>{value.email}</h3>
<p>{value.message}</p>
<p>{value.createdAt}</p>
</div>
);
}
});
export default class EmailsViewer extends Component {
render() {
return (
<div className="emails">
<h1>Sos</h1>
{viewMails}
</div>
);
}
}```
Since you are trying to do a simple component to show a list, if you're using one of the last version of React, consider using axios hook (check the package documentation to see how to add it to your project https://www.npmjs.com/package/axios-hook)
Here I show you an example of what you need to do: list demo

Resources