Error while loading a basic react-leaflet map - react-leaflet

I am new to react-leaflet.
I'm working on a Flask React project and I'm trying to load a react-leaflet map.
I'm getting the below error :
Uncaught TypeError: Cannot use 'in' operator to search for 'default' in undefined
at react-leaflet.js:7
at React__default (react-leaflet.js:4)
at react-leaflet.js:5
Versions :
react-leaflet : v1.9.1
leaflet.css : v1.3.1
react-leaflet.js : v1.9.1
I have added the necessary routes for rendering the Appbody.
But I'm unable to figure out what is wrong.
import React, {Component} from 'react'
import {Map, Marker, Popup, TileLayer} from 'react-leaflet'
const position = [51.505, -0.09]
class MainMap extends Component {
render() {
return (
<div>
<Map center={position} zoom={13}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution="© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
/>
<Marker position={position}>
<Popup>
<span>A pretty CSS3 popup.<br/>Easily customizable.</span>
</Popup>
</Marker>
</Map>
</div>
);
}
}
export default MainMap;
import React, {Component} from 'react';
import MainMap from "./map";
class AppBody extends Component {
render() {
return (
<div>
<MainMap/>
</div>
);
}
}
export default AppBody;
.leaflet-container {
position: absolute;
height: 100%;
width: 100%;
}

I'm currently using react-leaflet and I never had this kind of error, but I can see something wrong in the code (I don't know if those resolve the problem).
Firstly have you imported the leaflet.css file? You need to import this in the index.js or in the current file
import "leaflet/dist/leaflet.css";
You have also to add a ref props in the map component like this
<Map ref = "map" {...otherprops} >

I think the only problem in your code is surrounding the Map element by div tags.
So if you remove them and make the Map element at the top, then the problem should be solved.

TL;DR
Do not include the react-leaflet CDN in your index.html if you have installed it with npm or yarn.
Well, after much probing around with the problem myself I think you may have set up things incorrectly in the <head> of your index.html, this is how I had it set up before with the error happening:
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-leaflet/2.0.0/react-leaflet.js"></script>
and solving the issue:
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""/>
Notice the difference? If you have installed react-leaflet with npm or yarn, you'll see that you don't need to add the leaflet script in your <head>. What was happening before is that the react-leaflet script was loading before the webpacked js files and it therefore could not find React. The react-leaflet source code that threw the error looked like this:
var React__default = 'default' in React ? React['default'] : React;
And obviously, if there was no React object in the first place, there will be an error when trying to find the 'default' key.
Hope this helps someone some day!

Related

React Leaflet Map not displaying

I have the basic example from React-leaflet, but for the life of me I cannot get anything to display. I am using this fix from Jeremy Monson for the common babel-loader issue. I was having the same problems of no display when I went through the manual fixes. Right now I am using styled-components, but I was having the same issue with regular CSS. My map component page looks like this.
import React from 'react'
import styled from '#emotion/styled'
import { MapContainer, TileLayer, Marker, Popup } from '#monsonjeremy/react-leaflet'
const Leaflet = styled.div`
height:500px;
width:500px;
`
const Map = () => {
return (
<Leaflet>
<MapContainer center={[51.505, -0.09]} zoom={13} scrollWheelZoom={false}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[51.505, -0.09]}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>
</Leaflet>
)
}
export default Map
I am loading the leaflet css in the of head my index.html page. I am importing my map component in App.js and rendering it there.
Any thoughts or pointing in the right direction would be much appreciated.
Add height to your map container using style prop:
<MapContainer
center={[51.505, -0.09]}
zoom={13}
scrollWheelZoom={false}
style={{height: '100%'}} // Add a height
>
...

Document null when testing with Testing Library

I'm trying to test a single component in my react app and getting the following error:
TypeError: Cannot read property 'clientWidth' of null
20 |
21 | resize = () => {
> 22 | const contentWidth = document.getElementById('root').clientWidth;
Here's the test:
import React from 'react'
import { MemoryRouter } from 'react-router-dom'
import { render, screen } from '#testing-library/react';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from '../store/reducer';
import Navigation from '../App/layout/AdminLayout/Navigation'
const store = createStore(reducer);
describe('Menu', () => {
it('Estate Planning points to classic estate planning page', () => {
render(
<MemoryRouter>
<Provider store={store}>
<Navigation />
</Provider>
</MemoryRouter>
);
screen.debug()
})
})
I tried with defining the container render(..., { container: document.body}), but got the same error. I'm not sure what I'm missing.
You are getting this error because your document does not contain an element with id "root" when running a test with react-testing-library. This is likely because react-testing-library renders your component to a different container than ReactDOM (which is used to run your application).
The Problem
Let's look at a typical React application setup.
<!-- public/index.html -->
<html>
<body>
<div id="root"></div>
</body>
</html>
// src/index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
ReactDOM.render(<App />, document.querySelector("#root"));
// src/components/App.js
import React from "react";
const App = () => <div>Hello World!</div>;
export default App;
As we can see, index.js looks for an HTML element with an id of "root" and renders our App component inside that element. We can confirm that is happening by inspecting the element in your browser's developer tools:
<html>
<body>
<div id="root">
<div>Hello World!</div>
</div>
</body>
</html>
Now, let's write a simple test, and see what the DOM looks like.
// src/components/App.test.js
import React from "react";
import { render, screen } from "#testing-library/react";
import App from "./App";
test("renders the component", () => {
render(<App />);
screen.debug();
});
screen.debug() prints the DOM for debugging purposes. We can see that it does not include an element with id "root":
<body>
<div>
<div>
Hello World!
</div>
</div>
</body>
So the DOM container is slightly different for your test vs. runtime.
The Solution
One way to fix this problem is to refactor your code not to be dependent on the "root" element. Another option is to tell react-testing-library to render your component in a custom container. Here is an example of what that might look like:
// src/components/App.test.js
import React from "react";
import { render, screen } from "#testing-library/react";
import App from "./App";
test("renders the component in a specific container", () => {
const container = document.createElement("div");
container.id = "root";
render(<App />, { container: document.body.appendChild(container) });
screen.debug();
});
Now, we can see an element with id of "root" in the DOM, so your component should be able to find that element.
<body>
<div id="root">
<div>
Hello World!
</div>
</div>
</body>

How to insert a Link into a GridListTile in Gatsby

I am trying to have a clickable grid of images within Gatsby using the Material-UI GridList
Inside the GridListTile I am not able to put a Gatsby Link around my image or inside the GridListTileBar.
export default function SingleLineGridList() {
const classes = useStyles();
return (
<div className={classes.root}>
<GridList className={classes.gridList} cols={1.5} cellHeight="300">
{tileData.map(tile => (
<GridListTile key={tile.img} className={classes.gridListTile}>
<Link to={`product/1`}>
<img src={tile.img} alt={tile.title} />
</Link>
<GridListTileBar
title={tile.title}
classes={{
root: classes.titleBar,
title: classes.title,
}}
/>
</GridListTile>
))}
</GridList>
</div>
);
}
I get the error 'TypeError: Cannot read property 'muiName' of undefined'
I have found similar examples from straight react so presume it is something to do with the Gatsby link component
I realise it is likely to have something to do with component wrapping but have no idea how to implement this.
How can I make the Gatsby Link element an accepted element with the GridListTile?

How I can use my jquery plugin in Next.js?

i'm developing web app using Next.js and I'd like to use jQuery in Next.js.
But I can't import jquery plugin.
please check my code and Help me.
import React from 'react';
import Document, { Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from 'styled-components';
export default class MyDocument extends Document {
static getInitialProps({ renderPage }) {
const sheet = new ServerStyleSheet();
const page = renderPage(App => props => sheet.collectStyles(<App {...props} />));
const styleTags = sheet.getStyleElement();
return { ...page, styleTags };
}
render() {
return (
<html lang="en">
<Head>{this.props.styleTags}
<link
href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0/katex.min.css"
rel="stylesheet"
/>
<script src="../static/js/jquery.main.js" async/>
</Head>
<body>
<Main />
<div id="modal" />
<NextScript />
</body>
</html>
);
}
}
One typical issue you will get into if you do jQuery is, After importing the jQuery plugins they will register for onClick events, and by that time you can't guarantee that the actual DOM Element is ready, elements may get created later and may get refreshed.
One way of solving the issues is call the jQuery code which does the initialization in componentDidMount() and also in componentDidUpdate() so that you can make sure the DOM elements are present before the jQuery plugin register them.

Vue.js page transition fade effect with vue-router

How to achieve a fade effect page transition between vue-router defined pages (components)?
Wrap <router-view></router-view> with <transition name="fade"></transition> and add these styles:
.fade-enter-active, .fade-leave-active {
transition-property: opacity;
transition-duration: .25s;
}
.fade-enter-active {
transition-delay: .25s;
}
.fade-enter, .fade-leave-active {
opacity: 0
}
Detailed answer
Assuming you have created your application with vue-cli, e.g.:
vue init webpack fadetransition
cd fadetransition
npm install
Install the router:
npm i vue-router
If you are not developing your app using vue-cli, make sure to add the vue router the standard way:
<script src="/path/to/vue.js"></script>
<script src="/path/to/vue-router.js"></script>
You can use e.g.: https://unpkg.com/vue-router/dist/vue-router.js
The CLI has created a backbone application for you, which you can add components to.
1) Create page components
In Vue, components (UI elements) can be nested. A page in your app can be made with a regular Vue component that is considered as the root to other components in that page.
Go to src/ and create pages/ directory. These page-root components (individual pages) will be put in this directory, while the other components used in the actual pages can be put to the ready-made components/ directory.
Create two pages in files called src/pages/Page1.vue and src/pages/Page2.vue for starters. Their content will be (edit page numbers respectively):
<template>
<h1>Page 1</h1>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
2) Setup routing
Edit the generated src/main.js add the required imports:
import VueRouter from 'vue-router'
import Page1 from './pages/Page1'
import Page2 from './pages/Page2'
Add a global router usage:
Vue.use(VueRouter)
Add a router setup:
const router = new VueRouter({
routes: [
{ path: '/page1', component: Page1 },
{ path: '/page2', component: Page2 },
{ path: '/', redirect: '/page1' }
]
})
The last route just redirects the initial path / to /page1. Edit the app initiation:
new Vue({
router,
el: '#app',
render: h => h(App)
})
The whole src/main.js example is at the end of the answer.
3) Add a router view
Routing is set up by now, just a place where the page components will be rendered according to the router is missing. This is done by placing <router-view></router-view> somewhere in the templates, you will want to put it in the src/App.vue's <template> tag.
The whole src/App.vue example is at the end of the answer.
4) Add fade transition effect between page components
Wrap the <router-view></router-view> with a <transition name="fade"> element, e.g.:
<template>
<div id="app">
<transition name="fade">
<router-view></router-view>
</transition>
</div>
</template>
Vue will do the job here: it will create and insert appropriate CSS classes starting with the name specified through-out the effect's duration, e.g.: .fade-enter-active. Now define the effects in App.vue's section:
<style>
.fade-enter-active, .fade-leave-active {
transition-property: opacity;
transition-duration: .25s;
}
.fade-enter-active {
transition-delay: .25s;
}
.fade-enter, .fade-leave-active {
opacity: 0
}
</style>
That's it. If you run the app now, e.g. with npm run dev, it will automatically display Page 1 with a fade-in effect. If you rewrite the URL to /page2, it will switch the pages with fade-out and fade-in effects.
Check out the documentation on routing and transitions for more information.
5) Optional: Add links to pages.
You can add links to particular pages with the <router-link> component, e.g.:
<router-link to="/page1">Page 1</router-link>
<router-link to="/page2">Page 2</router-link>
This automatically gives the links a router-link-active class in case they are active, but you can also specify custom classes if you are using e.g. Bootstrap:
<router-link class="nav-link" active-class="active" to="/page1">Page 1</router-link>
<router-link class="nav-link" active-class="active" to="/page2">Page 2</router-link>
Files for reference
src/main.js:
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
import Page1 from './pages/Page1'
import Page2 from './pages/Page2'
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{ path: '/page1', component: Page1 },
{ path: '/page2', component: Page2 },
{ path: '/', redirect: '/page1' }
]
})
/* eslint-disable no-new */
new Vue({
router,
el: '#app',
render: h => h(App)
})
src/App.vue:
<template>
<div id="app">
<router-link class="nav-link" active-class="active" to="/page1">Page 1</router-link>
<router-link class="nav-link" active-class="active" to="/page2">Page 2</router-link>
<transition name="fade">
<router-view></router-view>
</transition>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
<style>
.fade-enter-active, .fade-leave-active {
transition-property: opacity;
transition-duration: .25s;
}
.fade-enter-active {
transition-delay: .25s;
}
.fade-enter, .fade-leave-active {
opacity: 0
}
</style>
src/pages/Page1.vue:
<template>
<h1>Page 1</h1>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
src/pages/Page2.vue:
<template>
<h1>Page 2</h1>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
Plug and Play Solution
There is also a plug and play solution called vue-page-transition which offers you all sort of transitions. (fade, flip, zoom, overlay etc.)
1 - Install the npm package:
yarn add vue-page-transition
2 - register the plugin:
import Vue from 'vue'
import VuePageTransition from 'vue-page-transition'
Vue.use(VuePageTransition)
3 - wrap your router-view with the global animation:
<vue-page-transition name="fade-in-right">
<router-view/>
</vue-page-transition>
Learn more on GitHub:
https://github.com/Orlandster/vue-page-transition