React LeafletJs Map doesn't re-render even on state change? [duplicate] - javascript

I'm a new leaflet user for my Typescript and Hook based React application. In my app my current geolocation position(latitude, longitude) is taken(I've allowed the permission to the browser) using the chrome browser's geolocation API by the app and should be shown in the map with a marker. The issue is, the map is always displayed with the initial default position([0,0]). That is, the new position update taken from geolocation API is not displayed.
The issue might be simple but I couldn't understand what I'm missing here that the Leaflet map is not taking my updated position. I checked, new position values are printed correctly, even I rendered just the updated position values inside a simple div, the new values are rendered correctly. Here is my code as below. Any help is much appreciated.
App.tsx
import React from 'react';
import './App.css';
import { Container } from '#material-ui/core';
import {Route,Switch} from 'react-router-dom';
import Header from './components/Header';
import SideBar from './components/SideBar';
import ShowInGoogleMap from './components/ShowInGoogleMap';
import ShowInLeafletMap from './components/ShowInLeafletMap';
function App() {
return (
<div className="app-div">
<Header/>
<div className="main-content">
<SideBar/>
<div className="map-content">
<Switch>
<Route path="/google-map" component={ShowInGoogleMap}/>
<Route path="/leaflet-map" component={ShowInLeafletMap}/>
</Switch>
</div>
</div>
</div>
);
}
export default App;
###############################
ShowInLeafletMap.tsx - this is the function handling Leaflet map
import { LatLngExpression } from 'leaflet';
import React, { useState, useEffect } from 'react';
import 'leaflet/dist/leaflet.css';
import { MapContainer, Marker, Popup, TileLayer } from 'react-leaflet';
const ShowInLeafletMap = () => {
const [position, setPosition] = useState<LatLngExpression>([0,0]);
useEffect(() => {
if ("geolocation" in navigator) {
console.log("Available...");
navigator.geolocation.getCurrentPosition(function(cPosition) {
console.log("Latitude is :", cPosition.coords.latitude);
console.log("Longitude is :", cPosition.coords.longitude);
setPosition([cPosition.coords.latitude,cPosition.coords.longitude]);
});
} else {
console.log("Not Available");
}
}, []);
console.log('this is loaded, ', position);
return(
<MapContainer center={position} zoom={13} scrollWheelZoom={false}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={position}>
<Popup>
Hi I just found Dresden
</Popup>
</Marker>
</MapContainer>
)
}
export default ShowInLeafletMap;
Here is dependency block of my package.json. I've no dev dependecies for the time being.
"dependencies": {
"#material-ui/core": "^4.11.4",
"#testing-library/jest-dom": "^5.11.4",
"#testing-library/react": "^11.1.0",
"#testing-library/user-event": "^12.1.10",
"#types/googlemaps": "^3.43.3",
"#types/jest": "^26.0.15",
"#types/node": "^12.0.0",
"#types/react": "^17.0.0",
"#types/react-dom": "^17.0.0",
"#types/react-leaflet": "^2.8.1",
"#types/react-router-dom": "^5.1.7",
"leaflet": "^1.7.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-leaflet": "^3.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1"
},

In react-leaflet version 3, most props are immutable. As for the MapContainer itself:
Except for its children, MapContainer props are immutable: changing them after they have been set a first time will have no effect on the Map instance or its container.
You're better off using the whenCreated prop to capture a reference to the underlying L.map instance in a state variable, then using leaflet methods directly:
const ShowInLeafletMap = () => {
const [map, setMap] = useState<L.Map>()
useEffect(() => {
if ("geolocation" in navigator && map) {
navigator.geolocation.getCurrentPosition(function(cPosition) {
map.panTo([cPosition.coords.latitude,cPosition.coords.longitude]);
});
}
}, [map])
return (
<MapContainer whenCreated(setMap)>
...
</MapContainer>
)
}
Working codesandbox

In leaflet v.4 I used this anti-pattern to rerender (wondering about their documentation):
<MapContainer key={new Date().getTime()} ...>

Related

rootRef.current.contains is not a function on react-transition-group Transition Component on latest React and MUI v5?

I am migrating a project from Material-UI 4 to MUI v5, where I also upgraded react to v18. We are using Transition from react-transition-group on one of our components, inside of a Modal. I get a rootRef.current.contains is not a function error on a TrapFocus component. I am not using a TrapFocus component.
Here is my codesandbox example:
https://codesandbox.io/s/wizardly-pare-gx08dc?file=/demo.js:0-847
import React from "react";
import { Transition } from "react-transition-group";
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false
};
}
render() {
const { open } = this.state;
return (
<>
<button
onClick={() => {
this.setState({ open: true });
}}
>
Click Me
</button>
<Modal
open={open}
onClose={() => {
this.setState({ open: false });
}}
>
<Transition
in={open}
timeout={{
enter: 0,
exit: 500
}}
>
<div>Hello</div>
</Transition>
</Modal>
</>
);
}
}
export default Demo;
My environment is as follows:
"#emotion/react": "^11.9.3",
"#emotion/styled": "^11.9.3",
"#mui/icons-material": "^5.8.4",
"#mui/material": "^5.9.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-transition-group": "^4.4.2"
Any help on this would be appreciated.
Thank you
Alright, turns out I have to wrap the Transition in a div. but idk why that fixes this

When using #react-three/drei useGLTF crashes scene

Hi everyone I'm kind of driving myself crazy with this, but I am trying to set up a simple three.js scene, however when I try to use the useGLTF function from #react-three/drei the scene crashes, and my console says:
Warning: meshopt_decoder is using experimental SIMD support
The above error occurred in the <ForwardRef(Canvas)> component:
at Canvas (http://localhost:3000/_next/static/chunks/pages/index.js?ts=1630506543315:10124:3)
at div
at Layout (http://localhost:3000/_next/static/chunks/pages/index.js?ts=1630506543315:502:23)
at Home
at wrappedComponent (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1630506543315:457:73)
at wrappedComponent (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1630506543315:457:73)
at ErrorBoundary (http://localhost:3000/_next/static/chunks/main.js?ts=1630506543315:764:47)
at ReactDevOverlay (http://localhost:3000/_next/static/chunks/main.js?ts=1630506543315:880:23)
at Container (http://localhost:3000/_next/static/chunks/main.js?ts=1630506543315:8865:5)
at AppContainer (http://localhost:3000/_next/static/chunks/main.js?ts=1630506543315:9361:24)
at Root (http://localhost:3000/_next/static/chunks/main.js?ts=1630506543315:9500:25)
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.
THREE.WebGLRenderer: Context Lost.
My react scene looks like this:
import React, { Suspense } from 'react'
import { Canvas } from '#react-three/fiber'
import Layout from '../components/layout'
import { Sky, OrbitControls, useGLTF } from '#react-three/drei'
const Skull = () => {
const { nodes, materials } = useGLTF('skull.gltf')
console.log(nodes)
return (
<Suspense fallback={null}>
<mesh geometry={nodes.mesh_0.geometry} />
</Suspense>
)
}
export default function Home() {
return (
<Layout>
<Canvas>
<Sky sunPosition={[0, 1, 0]} />
<Skull />
<OrbitControls />
</Canvas>
</Layout>
)
}
And my packages:
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"#material-ui/core": "^4.12.3",
"#material-ui/lab": "^4.0.0-alpha.60",
"#react-three/drei": "^7.5.0",
"#react-three/fiber": "^7.0.6",
"add": "^2.0.6",
"axios": "^0.21.1",
"mobx": "^6.3.2",
"mobx-react": "^7.2.0",
"next": "11.1.2",
"react": "17.0.2",
"react-dom": "17.0.2",
"sass": "^1.38.2",
"three": "^0.132.2",
"three-stdlib": "^2.4.0",
"yarn": "^1.22.11"
},
"devDependencies": {
"esbuild-loader": "^2.15.1",
"eslint": "7.32.0",
"eslint-config-next": "11.1.2"
}
}
I can't figure out what is going on here and the console errors are not descriptive enough for me to understand. Is there some obvious step I am missing here?
Thanks!
I was eventually able to figure out a way to get everything to work. I had to add a call to preload the gltf file and then everything ran okay. I updated my default component to look like this:
export default function Home() {
useGLTF.preload("skull.gltf")
return (
<Layout>
<Canvas>
<Sky sunPosition={[0, 1, 0]} />
<Skull />
<OrbitControls />
</Canvas>
</Layout>
)
}
After this I got no errors loading the scene and everything worked as intended.

No get query sting data in react

I'm trying to get query string parameters tho, it's blank.
This is URL.
https://master.deeiswmgeowge.amplifyapp.com/?site=gfg&subject=react
Then, this.props is empty.
The below is the source.
import React, { Component } from "react";
// Importing Module
import queryString from 'query-string'
class App extends Component {
state = {
site: 'unknown',
subject: 'i dont know'
}
handleQueryString = () => {
// Parsing the query string
// Using parse method
console.log(`this.props`, this.props)
let queries = queryString.parse(this.props.location.search)
console.log(queries)
this.setState(queries)
}
render() {
return (
<div style={{ margin: 200 }}>
<p> WebSite: {this.state.site} </p>
<p> Subject: {this.state.subject} </p>
<button
onClick={this.handleQueryString}
className='btn btn-primary'>
click me
</button>
</div>
);
}
}
export default App;
"dependencies": {
"#testing-library/jest-dom": "^5.11.4",
"#testing-library/react": "^11.1.0",
"#testing-library/user-event": "^12.1.10",
"query-string": "^6.14.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.2",
"web-vitals": "^1.0.1"
},
This is the error image.
You're not using react router , thus no location parameter in props :
so you have two solution ,
1 whether adding react-router-dom and wrap your app with router , ( or using with router hook like export default withRouter(App))
2 or access directly window.location.search and get params with URLSearchParams
by example :
const urlParams = new URLSearchParams(window.location.search);
const site = urlParams.get('site');
const subject = urlParams.get('subject');
Need to pass the props like
onClick={()=> this.handleQueryString(this.props)}
and received like
handleQueryString(arg) {
....
}

Cornerstone Tools do not work (after following doc)

first of all,please be patient with this post, because this is my first question here on the platform.
Currently I'm trying to display some .dcm images using Cornerstone. This has worked and looks good.
But since a few days I have the problem that I can't get a simple tool from Cornerstone tools to work with it.
My goal was to start with the wwwc-tool and then the stack-scrolling.
I worked strictly after documentation, but it is simply not possible for me to include any tool. I just don't see the error and don't get any error output.
Can you help me with that?
import React, { useState, useEffect, useRef } from "react";
import { makeStyles } from "#material-ui/core/styles";
import cornerstone from "cornerstone-core";
import cornerstoneMath from "cornerstone-math";
import cornerstoneTools from "cornerstone-tools";
import Hammer from "hammerjs";
cornerstoneTools.external.cornerstone = cornerstone;
cornerstoneTools.external.Hammer = Hammer;
cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
cornerstoneTools.init();
export default function Dummy() {
const dicomRef = useRef();
const imageIds = [
"wadouri:http://127.0.0.1:8080/api/challenges/1/series/1/images/1",
"wadouri:http://127.0.0.1:8080/api/challenges/1/series/2/images/1",
"wadouri:http://127.0.0.1:8080/api/challenges/1/series/3/images/1",
];
// define the stack
const stack = {
currentImageIdIndex: 0,
imageIds,
};
// Add our tool, and set it's mode
const { LengthTool } = cornerstoneTools;
useEffect(() => {
// Enable the DOM Element for use with Cornerstone
const element = document.getElementById("navbar");
cornerstone.enable(element);
cornerstone.loadImage(`${imageIds[0]}`).then((image) => {
cornerstone.displayImage(element, image);
cornerstoneTools.addTool(LengthTool);
cornerstoneTools.addToolForElement(element, LengthTool);
cornerstoneTools.setToolActive(LengthTool.name, { mouseButtonMask: 1 });
});
}, []);
return <div ref={dicomRef}>aaa</div>;
}
My dependencys are as follow:
"dependencies": {
"#material-ui/core": "^4.9.14",
"#material-ui/icons": "^4.9.1",
"bootstrap": "^4.5.0",
"cornerstone-core": "^2.2.4",
"cornerstone-math": "^0.1.6",
"cornerstone-tools": "^3.19.3",
"cornerstone-wado-image-loader": "^3.1.1",
"daikon": "^1.2.42",
"dicom-parser": "^1.8.5",
"hammerjs": "^2.0.8",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-lottie-light": "^1.2.5",
"react-scripts": "3.4.1"},
I just want to display the Viewer with the tools in returning div.
Can you try changing useEffect() to:
useEffect(() => {
// Enable the DOM Element for use with Cornerstone
const element = document.getElementById("navbar");
cornerstone.enable(element);
cornerstone.loadImage(`${imageIds[0]}`).then((image) => {
const viewport = cornerstone.getDefaultViewportForImage(element, image);
cornerstone.displayImage(element, image, viewport);
const LengthTool = cornerstoneTools.LengthTool;
cornerstoneTools.addTool(LengthTool)
cornerstoneTools.setToolActive('Length', { mouseButtonMask: 1 })
});
}, []);

Cannot read property 'replaceChild' of null URL: webpack:///./~react-dom/lib/DOMLazyTree.js

I am using phonegap to create an app using react v15 and "webpack": "^2.2.1" to bundle up everything. I then run my webpack.prod.json to generate a stand alone .js file which is included in the app.
When I install the app locally, I have no problems and can run the application, however when I build through phonegap.com/build is when the issue occurs.
Even weirder still is that the initial state loads fine. Its when I navigate to #/home that this error occurs:
Uncaught SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse (<anonymous>)
at RequireLogin.render (RequireLogin.js:32)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (ReactCompositeComponent.js:799)
at ReactCompositeComponentWrapper._renderValidatedComponent (ReactCompositeComponent.js:822)
at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:362)
at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
at Object.mountComponent (ReactReconciler.js:46)
at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:371)
at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
at Object.mountComponent (ReactReconciler.js:46)
RequireLogin.js
import React from 'react';
import {connect} from 'react-redux';
import {Redirect} from 'react-router'
class BlockForLoggedInUsers extends React.Component {
constructor(props){
super(props);
}
render(){
const loggedIn = this.props.user.loggedIn || JSON.parse(localStorage.LOGGED_IN);
if (loggedIn) {
return (
<Redirect push to="/home"/>
)
}else{
return (
<div></div>
);
}
}
}
function mapStateToProps(state){
return {
user: state.user
};
}
export default connect(mapStateToProps)(BlockForLoggedInUsers);
Then, when I hit the back key I get a different error:
DOMLazyTree.js:69 Uncaught TypeError: Cannot read property 'replaceChild' of null
at Function.replaceChildWithTree (DOMLazyTree.js:69)
at Object.dangerouslyReplaceNodeWithMarkup [as replaceNodeWithMarkup] (Danger.js:41)
at ReactCompositeComponentWrapper._replaceNodeWithMarkup (ReactCompositeComponent.js:784)
at ReactCompositeComponentWrapper._updateRenderedComponent (ReactCompositeComponent.js:774)
at ReactCompositeComponentWrapper._performComponentUpdate (ReactCompositeComponent.js:724)
at ReactCompositeComponentWrapper.updateComponent (ReactCompositeComponent.js:645)
at ReactCompositeComponentWrapper.receiveComponent (ReactCompositeComponent.js:547)
at Object.receiveComponent (ReactReconciler.js:125)
at Object.updateChildren (ReactChildReconciler.js:109)
at ReactDOMComponent._reconcilerUpdateChildren (ReactMultiChild.js:213)
The problem I have with this is it means that the app is loading well, but I assume something in my #/home component is broken, but I have stripped this back to be nothing but a div.
All packages noteworthy:
"history": "^4.5.1",
"react": "^15.5.0",
"react-css-modules": "^4.1.0",
"react-dom": "^15.5.0",
"react-redux": "^5.0.3",
"react-router": "^4.1.1",
"react-router-dom": "^4.0.0",
"react-router-redux": "^5.0.0-alpha.6",
"react-tap-event-plugin": "^2.0.1",
"redux": "^3.6.0",
"webpack": "^2.2.1"
Router.js
export default class Routes extends Component {
render() {
return (
<div>
<Route exact path="/" component={Splash}/>
<Route path="/signin" component={SignIn} />
<Route path="/logout" component={Logout} />
<Route path="/home" component={Home} />
<Route path="/settings" component={Settings} />
<Route path="/sextypeselection" component={SexTypeSelection} />
<Route path="/desire" component={Desire} />
</div>
)
}
};
home/index.js
import React from 'react';
import { bindActionCreators } from 'redux'
import { RequireLogin } from '../shared/auth/userRedirects'
import mobiscroll from '../shared/mobiscroll/mobiscroll.custom';
import * as currentSexInfo from '../../actions/currentSexInfo'
import {connect} from 'react-redux';
//Header
import Header from '../shared/header/Header';
import RightPlus from '../shared/header/RightPlus';
import Menu from '../shared/menu';
//Styles
import HomeStyle from './home.css';
class Home extends React.Component {
constructor (props){
super(props);
console.info(props);
const now = new Date();
this.state = {
settings : {
display: 'inline',
yearChange: false,
marked: [
new Date(2017, 5, 4)
]
, max: new Date()
// , showOuterDays: false
}
};
this.selectData = this.selectData.bind(this);
}
selectData = (event, inst) => {
if(event.control) {
this.props.DispatchChangeCurrentSexInfo(event.date);
window.location.hash = 'sextypeselection';
}
};
onPosition = (ev) => {
let $ = mobiscroll.$,
monthCont = $('.mbsc-cal-anim-c', ev.target),
calHeight = document.body.offsetHeight - 375;
monthCont.height('');
monthCont.height(calHeight);
};
render(){
return (
<div>
<RequireLogin />
<Header right={<RightPlus link="sextypeselection" />} />
<div className={HomeStyle.home}>
<div className="pageInfo">
<h1>My calender</h1>
<p>Select a date to view <br/> input your information</p>
</div>
<div className={"cal " + HomeStyle.calenderContainer}>
<mobiscroll.Calendar onPosition={this.onPosition} onSetDate={this.selectData} options={this.state.settings} {...this.props} />
</div>
</div>
<Menu />
</div>
);
}
}
function matchDispatchToProps(dispatch){
return {DispatchChangeCurrentSexInfo : bindActionCreators(currentSexInfo.changeCurrentSexInfo, dispatch)}
}
export default connect(null,matchDispatchToProps)(Home);
Sadly it was simple in the end, I doubt anybody will have this same problem but in the end it was JSON.parse trying to work on an undefined item.
The fix:
const storage = localStorage.LOGGED_IN || {};
const loggedIn = this.props.user.loggedIn || JSON.parse(JSON.stringify(storage));
Here
In react-domlibrary >>
DOMLazyTree.js
oldNode get in null, and hence parentNode get in undefind for replaceChild function.
function replaceChildWithTree(oldNode, newTree) {
oldNode.parentNode.replaceChild(newTree.node, oldNode);
insertTreeChildren(newTree);
}
So make sure oldNode.parentNode would be fulfilled with required data.

Categories

Resources