NextJS and persist layout that contains Leaflet - reactjs

I'm migrating a project from React to NextJS which has a layout where the common component is a Leaflet Map.
In Next JS, the "next/dynamic" used to load the map
React used react-router-dom#v6
next layout
Layout code:
import dynamic from "next/dynamic";
import React, { useMemo, useState } from "react";
const DynamicLeafletMap = dynamic(
() => import("../components/LeafletMap/LeafletMap"),
{
ssr: false,
}
);
function Layout({ children }) {
return (
<main>
<DynamicLeafletMap />
{children}
</main>
);
}
export default Layout;
_app.js code:
import Layout from "../components/Layout";
import "../styles/globals.scss";
function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
export default MyApp;
LeafletMap.jsx
import { MapContainer, TileLayer } from "react-leaflet";
import styles from "./LeafletMap.module.scss";
const initial_position = [38.9637, 35.2433];
function LeafletMap() {
return (
<>
<div className={styles.map}>
<MapContainer
center={initial_position}
zoom={4}
scrollWheelZoom={true}
className={styles.map__container}
>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>
</div>
</>
);
}
export default LeafletMap;
The problem is that when using "router.push" (for example, clicking on a marker should open a modal window on top of the map), the map is rerendered and reseted.
I tried different ways like useMemo, createPortal but this didn't work.
Is there a way to fix this behaviour? Maybe there is another framework that provides functionality like "persist layout"?

Next13 with new app directory or Remix solves this problem.

Related

Is my react getting loaded before showing up?

This is my App.js and earlier I was using Suspense but it does not seem to be working as it is not able to load the image and the font after the loader.
import React, { Suspense } from 'react';
import './App.css';
import SyncLoader from "react-spinners/SyncLoader";
const Newhome = React.lazy(() => import('./COMPONENTS/Newhome'));
function App() {
return (
<>
{
window.onload = <Newhome/>
}
{/* <Suspense className='App' fallback={
<SyncLoader size={'20px'} color='#FF5757' className='loader App'/>
}>
<Newhome />
</Suspense> */}
</>
);
}
export default App;
I have commented the Suspense tag part for now.
What can do so that the image, jsx, fonts, and everything loads and then the page is shown?

React & Typescript Issue: trigger elements with InsertionObserver using props and manage them in other component

Small premise: I'm not a great Typescript expert
Hi everyone, I'm working on my personal site, I decided to develop it in Typescript to learn the language.
My component tree is composed, as usual, of App.tsx which render the sub-components, in this case Navbar.jsx and Home.jsx.
Below is the App.jsx code:
import './App.css';
import { BrowserRouter as Router, useRoutes } from 'react-router-dom';
import Home from './components/Home';
import Navbar from './components/Navbar';
import { useState } from 'react';
function App(){
const [navbarScroll,setNavbarScrool]=useState(Object)
const handleLocationChange = (navbarScroll : boolean) => {
setNavbarScrool(navbarScroll)
return navbarScroll
}
const AppRoutes = () => {
let routes = useRoutes([
{ path: "/", element: <Home handleLocationChange={handleLocationChange}/> },
{ path: "component2", element: <></> },
]);
return routes;
};
return (
<Router>
<Navbar navbarScroll={navbarScroll}/>
<AppRoutes/>
</Router>
);
}
export default App;
Here, instead, the Home.jsx code:
import { useInView } from 'react-intersection-observer';
import HomeCSS from "../styles/home.module.css"
import mePhoto from "../assets/me.png"
import { useEffect, useState } from 'react';
interface AppProps {
handleLocationChange: (values: any) => boolean;
}
export default function Home(props: AppProps){
const { ref: containerChange , inView: containerChangeIsVisible, entry} = useInView();
useEffect(()=>{
props.handleLocationChange(containerChangeIsVisible)
//returns false at first render as expected
console.log("Home "+containerChangeIsVisible)
},[])
return(
<>
<div className={`${ HomeCSS.container} ${containerChangeIsVisible? HomeCSS.container_variation: ''}`}>
<div className={HomeCSS.container__children}>
{/* when i scroll on the div the css change (this works)*/}
<h1 className={`${ HomeCSS.container__h1} ${containerChangeIsVisible? HomeCSS.container__h1_variation: ''}`}>My<br/> Name</h1>
<p>Computer Science student.</p>
</div>
<img src={mePhoto} className={HomeCSS.image_style}/>
</div>
<div ref={containerChange} style={{height:800,background:"orange"}}>
<p style={{marginTop:20}}>HIII</p>
</div>
</>
)
}
And Navbar.jsx:
import NavbarCSS from "../styles/navbar.module.css"
import acPhoto from "../assets/ac.png"
import { Link } from "react-router-dom";
import { useEffect, useState } from "react";
interface NavbarScroolProp{
navbarScroll:boolean
}
export default function Navbar(props:NavbarScroolProp){
const [scrollState,setScrollState]=useState(false)
const [pVisible,setpVisible] = useState('')
useEffect(()=>{
setTimeout(() => {
setpVisible("")
}, 3000)
setpVisible("100%")
},[])
//returns false also when should be true
console.log(props.navbarScroll)
return (
<>
{/*the props is undefined so the css doesn't change, i need to do this*/}
<nav className={`${props.navbarScroll?NavbarCSS.nav__variation:NavbarCSS.nav}`}>
<div className={NavbarCSS.nav_row}>
<div className={NavbarCSS.nav_row_container}>
<img src={acPhoto} className={NavbarCSS.image_style}/>
<p className={NavbarCSS.p_style} style={{maxWidth: pVisible}}>My name</p>
</div>
<div className={NavbarCSS.nav_row_tagcontainer}>
<Link className={NavbarCSS.nav_row_tag} to="/"> Home</Link>
<Link className={NavbarCSS.nav_row_tag} to="/"> About</Link>
<Link className={NavbarCSS.nav_row_tag} to="/"> Contact</Link>
</div>
</div>
</nav>
</>
);
}
In my application I want to change the background color whenever the div referring to the InsertionObserver ( I use "useInView" hook , from :https://github.com/thebuilder/react-intersection-observer) is displayed. The problem is that the div in question is in the Home.jsx component and I need to change the color of the divs in the navbar as well when the div in Home is triggered(or other components in case I need to in the future).
The question is: How can I dynamically trigger DOM elements of other components (to then perform certain operations) using the InsertionObserver ?
As you can see from the code I tried to create Props, but everything returns undefined and doesn't involve any changes.
I've tried without useEffect, without using the useInView hook, passing the object instead of the boolean value, but I can't find any solutions to this problem.
You would be of great help to me.
PS: I would like to leave the Navbar.jsx component where it is now, so that it is visible in all components.
Any advice or constructive criticism is welcome.

React leaflet map not correctly displayed even with leaflet.css import

I'm trying to create a map with reac-leaflet in ionic but I'm not displaying it correctly, also following this link: Missing Leaflet Map Tiles when using react-leaflet
WINDOW RESIZING FIX IT. What am I doing wrong on first login?
On first access this is the map:
After resizing:
Here the code.
In index.html
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css"/>
Home.tsx simplified.
import { Map, Marker, Popup, TileLayer } from 'react-leaflet';
function Home() {
return (
<IonPage>
<IonHeader>
<IonToolbar color="primary">
<IonTitle>Logged in ... </IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<Map center={[45.24,8.55]} zoom={13}>
<TileLayer
attribution='&copy OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[45.24,8.55]}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</Map>
</IonContent>
</IonPage>
)
}
export default Home;
In css file.
.leaflet-container {
height: 100%;
width: 100%;
}
Thank you.
I had the same problem with Ionic 5 and React Leaflet 3 and I solved like this:
In the page where you use the leaflet-react component (in your case Home), import the useIonViewDidEnter lifecycle method (see full docs) to know when the IonPage has finished animating, then trigger a window-resize event.
import { IonPage, useIonViewDidEnter, ... } from '#ionic/react';
function Home() {
/*
* trigger a 'window-resize' event when Page has finished,
* rendering and animating, so leaflet map can read a
* consistent height value
*/
useIonViewDidEnter(() => {
window.dispatchEvent(new Event('resize'));
});
return (
<IonPage>
... your Leaflet component...
</IonPage>
);
}
Is working well for me.
Let me know if it helps.
This is what I do currently and works for me:
windowDimensions.tsx
import { useState, useEffect } from 'react';
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height,
};
}
export default function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(
getWindowDimensions(),
);
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowDimensions;
}
app.js or componentfile.js
import useWindowDimensions from 'path/to/useWindowDimensions'; //in my case i saved it as app/utils/windowDimensions
<Map style={{height: mapHeight}} />
Note: app.js only consist of code relevant to the fix
<link href='https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.3/leaflet.css' rel='stylesheet'>
Try this

Material UI for React "Cannot read property of 'between'.. " when trying to use theme.breakpoints

Cannot read property of 'between' / 'up'.. when trying to use theme.breakpoints.between.
I've read through the other stackoverflow answers and some of the issues here: https://github.com/mui-org/material-ui/issues and the only solution seems to be using ThemeProvider or MuiThemeProvider, which I've tried but error still exists.
Component file:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/styles";
import Grid from "#material-ui/core/Grid";
import Logo from "../assets/logo/logo";
const styles = theme => ({
root: {
flexGrow: 1
},
logo: {
[theme.breakpoints.up("md")]: {
padding: "5em"
}
}
});
class Tools extends Component {
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<Grid container className={classes.logo}>
<Grid item className={classes.logo}>
<Logo name="some-logo" />
</Grid>
</Grid>
</div>
);
}
}
Tools.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(Tools);
App.js
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import MuiThemeProvider from "#material-ui/core/styles/MuiThemeProvider";
class App extends Component {
render() {
return (
<MuiThemeProvider>
<Router>
<div className="App">
<Switch>
<Route exact path="/" render={() => <Home />} />
</Switch>
</div>
</Router>
</MuiThemeProvider>
);
}
}
export default App;
I think withStyles should have been imported from "#material-ui/**core**/styles" in the component file.
Faced the same issue with sloppy installation of material-ui without checking the version used in the project.
Rolled back to the previous version (listed below) and the issue was resolved.
Rolled back versions of:
#emotion/react: 11.4.1 from 11.5.0, and
#mui/material: 5.0.0 from 5.0.4

higer order component not displayed correctly

I m following tutorials to learn the concept of Hocs in React js the result of the tutorial should display in My browser like this :
toolbar,sideDrawer,backdrop
Burger
Build Controls
but it displayed like this :
toolbar,sideDrawer,backdrop
I cleaned cache in both browser and development server but nothing happened...so please any help or guide why this??Thanks in advance
Aux.js
const Aux = (props) => props.children
export default Aux;
Layout.js
import React from 'react';
import Aux from '../../hoc/Aux';
import classes from './Layout.css'
const Layout = ( props ) => (
<Aux>
<div>toolbar,sideDrawer,backdrop</div>
<main className={classes.Content}>
{props.childern}
</main>
</Aux>
);
export default Layout;
App.js
import React, { Component } from 'react';
import Layout from './components/Layout/Layout'
import BuliderBurger from './containers/BurgerBuilder/BurgerBuilder';
class App extends Component {
render () {
return (
<div>
<Layout>
<BuliderBurger/>
</Layout>
</div>
);
}
}
export default App;
BurgerBuilder.js
import React,{Component} from 'react';
import Aux from '../../hoc/Aux';
class BurgerBuilder extends Component {
render () {
return (
<Aux>
<div>Burger</div>
<div>Build Controls</div>
</Aux>
);
}
}
export default BurgerBuilder;
The reason is that you misspelt children in Layout, you spellt it childern. Fix the typo and it works...
const Layout = ( props ) => (
<Aux>
<div>toolbar,sideDrawer,backdrop</div>
<main className={classes.Content}>
{props.children}
</main>
</Aux>
);
import React, { Component } from 'react';
import Layout from './components/Layout/Layout'
import BuliderBurger from './containers/BurgerBuilder/BurgerBuilder';
class App extends Component {
render () {
return (
<div>
<Layout/>
<BuliderBurger/>
</div>
);
}
}
export default App;
Using Layout this can give the desired result

Resources