Reputation: 41
I am building a restaurant website template. In the project, I do have a modal box with two arrow buttons to change pages. I keep track of the pageNumber
variable via useState. Unfortunately, the value never updates, which prevents pages from changing.
Here is the Menu.js component:
import { BrowserRouter as Router, Link } from 'react-router-dom';
import { useState } from 'react';
const Menu = () => {
let [pageNumber, switchPage] = useState(1);
let dish = {
categories: [
'proin blandit',
'suspendisse non',
'fermentum ultrices',
'volutpat vulputat'
],
names: [
['Sed fermentum', 'Sapien nec lobortis', 'Tristique in suspendisse', 'Pellentesque mattis elit', 'Vel interdum velit'],
['Nam nisi quam', 'Donec non viverra', 'Morbi suscipit mattis', 'Sed dignissim nisi', 'Aliquam vitae'],
['Curabitur ante mi', 'Nulla a felis', 'Donec porta convallis ', 'Vestibulum viverra ', 'Nullam viverra '],
['Vestibulum odio', 'Mauris neque ligula', 'Praesent iaculis nunc', 'Cras sollicitudin est', 'Class aptent taciti ']
],
prices: [
[13.99, 11.99, 15.99, 17.99, 21.99],
[22.99, 20.99, 18.99, 16.99, 24.99],
[11.99, 21.99, 31.99, 25.99, 15.99],
[6.99, 8.99, 10.99, 4.99, 8.99]
]
}
let iterator = Math.abs(pageNumber % 4);
let lineBreak = window.innerWidth <= 750 ? <br/> : undefined;
return (
<Router>
<section className='menu'>
<i className='fas fa-chevron-circle-left' id='menu-arrow-left' onClick={() => switchPage(pageNumber - 1)}></i>
<h1 className='dish-category'>You are viewing {dish.categories[iterator]}</h1>
<Link to='/home'><i className='fas fa-times'></i></Link>
<ul className='dish-list'>
<li className='dish'>{dish.names[iterator][0]} {lineBreak} <span className='price'>{dish.prices[iterator][0]} PLN</span></li>
<li className='dish'>{dish.names[iterator][1]} {lineBreak} <span className='price'>{dish.prices[iterator][1]} PLN</span></li>
<li className='dish'>{dish.names[iterator][2]} {lineBreak} <span className='price'>{dish.prices[iterator][2]} PLN</span></li>
<li className='dish'>{dish.names[iterator][3]} {lineBreak} <span className='price'>{dish.prices[iterator][3]} PLN</span></li>
<li className='dish'>{dish.names[iterator][4]} {lineBreak} <span className='price'>{dish.prices[iterator][4]} PLN</span></li>
</ul>
<i className='fas fa-chevron-circle-right' id='menu-arrow-right' onClick={() => switchPage(pageNumber + 1)}></i>
</section>
</Router>
)
}
export default Menu;
This is how I toggle the modal's visibility:
const hideModal = (e) => {
e.preventDefault();
let placeholder = document.getElementById('placeholder');
placeholder.innerText = '';
placeholder.style.display = 'none';
let container = document.getElementById('container');
container.style.filter = '';
container.style.pointerEvents = 'auto';
}
const showModal = () => {
let placeholder = document.getElementById('placeholder');
placeholder.innerHTML = ReactDOMServer.renderToString(<Menu />);
placeholder.style.display = 'block';
let container = document.getElementById('container');
container.style.filter = 'blur(8px)';
container.style.pointerEvents = 'none';
}
And this is the corresponding JSX code in App.js:
<div id='placeholder'><Menu /> <Contact /></div>
Additionally, I have written a test function that detects the clicked place. When I run it on the example above I get a message that I am clicking outside the modal box, even though it's the opposite. The function is run from a different file. It looks like this:
let childrenNodes = [
document.getElementsByClassName('menu')[0],
document.getElementsByClassName('dish-category')[0],
document.getElementsByClassName('dish-list')[0],
document.getElementsByClassName('dish')[0],
document.getElementsByClassName('dish')[1],
document.getElementsByClassName('dish')[2],
document.getElementsByClassName('dish')[3],
document.getElementsByClassName('dish')[4],
document.getElementsByClassName('price')[0],
document.getElementsByClassName('price')[1],
document.getElementsByClassName('price')[2],
document.getElementsByClassName('price')[3],
document.getElementsByClassName('price')[4]
];
const detectPlace = () => {
window.addEventListener('click', (e) => {
childrenNodes.some((node) => e.target === node) ? console.log('Clicked inside!') : console.log('Clicked outside!');
console.log(e.target);
});
}
Could you tell me why is it working this way?
Upvotes: 0
Views: 78
Reputation: 21120
You are rendering the contents of #placholder
with:
let placeholder = document.getElementById('placeholder');
placeholder.innerHTML = ReactDOMServer.renderToString(<Menu />);
ReactDOMServer.renderToString(...)
produces a string containing HTML. This string doesn't include any JavaScript, thus making the result non-interactive.
renderToString()
ReactDOMServer.renderToString(element)
Render a React element to its initial HTML. React will return an HTML string. You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes.
If you call
ReactDOM.hydrate()
on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
If you want an interactive DOM structure you should use the normal ReactDOM.render(...)
method to render your component.
let placeholder = document.getElementById('placeholder');
ReactDOM.render(<Menu />, placeholder);
// import { BrowserRouter as Router, Link } from 'react-router-dom';
// import { useState } from 'react';
const { BrowserRouter: Router, Link } = ReactRouterDOM;
const { useState } = React;
const Menu = () => {
let [pageNumber, switchPage] = useState(1);
let dish = {
categories: [
'proin blandit',
'suspendisse non',
'fermentum ultrices',
'volutpat vulputat'
],
names: [
['Sed fermentum', 'Sapien nec lobortis', 'Tristique in suspendisse', 'Pellentesque mattis elit', 'Vel interdum velit'],
['Nam nisi quam', 'Donec non viverra', 'Morbi suscipit mattis', 'Sed dignissim nisi', 'Aliquam vitae'],
['Curabitur ante mi', 'Nulla a felis', 'Donec porta convallis ', 'Vestibulum viverra ', 'Nullam viverra '],
['Vestibulum odio', 'Mauris neque ligula', 'Praesent iaculis nunc', 'Cras sollicitudin est', 'Class aptent taciti ']
],
prices: [
[13.99, 11.99, 15.99, 17.99, 21.99],
[22.99, 20.99, 18.99, 16.99, 24.99],
[11.99, 21.99, 31.99, 25.99, 15.99],
[6.99, 8.99, 10.99, 4.99, 8.99]
]
}
let iterator = Math.abs(pageNumber % 4);
let lineBreak = window.innerWidth <= 750 ? <br/> : undefined;
return (
<Router>
<section className='menu'>
<i className='fas fa-chevron-circle-left' id='menu-arrow-left' onClick={() => switchPage(pageNumber - 1)}></i>
<h1 className='dish-category'>You are viewing {dish.categories[iterator]}</h1>
<Link to='/home'><i className='fas fa-times'></i></Link>
<ul className='dish-list'>
<li className='dish'>{dish.names[iterator][0]} {lineBreak} <span className='price'>{dish.prices[iterator][0]} PLN</span></li>
<li className='dish'>{dish.names[iterator][1]} {lineBreak} <span className='price'>{dish.prices[iterator][1]} PLN</span></li>
<li className='dish'>{dish.names[iterator][2]} {lineBreak} <span className='price'>{dish.prices[iterator][2]} PLN</span></li>
<li className='dish'>{dish.names[iterator][3]} {lineBreak} <span className='price'>{dish.prices[iterator][3]} PLN</span></li>
<li className='dish'>{dish.names[iterator][4]} {lineBreak} <span className='price'>{dish.prices[iterator][4]} PLN</span></li>
</ul>
<i className='fas fa-chevron-circle-right' id='menu-arrow-right' onClick={() => switchPage(pageNumber + 1)}></i>
</section>
</Router>
)
}
let placeholder = document.getElementById('placeholder');
ReactDOM.render(<Menu />, placeholder);
<div id="placeholder"></div>
<link crossorigin rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script crossorigin src="https://unpkg.com/react-router-dom@5/umd/react-router-dom.js"></script>
Upvotes: 1