Mapbox GL app with react and mapbox gl does not work - reactjs

I followed the tutorial on Mapbox using react and Mapbox GL and there are no problems related to the code but when I start the application on the browser(chrome) it shows a blank page with the coordinates.
it seems that the application itself works but it does not shows the Map.
this is my code:
html
<!DOCTYPE html>
<html lang='en'>
<head>
<title>Mapbox GL JS and React</title>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.3.1/mapbox-gl.css' rel='stylesheet' />
<link href='site.css' rel='stylesheet'/>
</head>
<body>
<div id='app'></div>
</body>
</html>
css:
.sidebarStyle {
display: inline-block;
position: absolute;
top: 0;
left: 0;
margin: 12px;
background-color: #404040;
color: #ffffff;
z-index: 1 !important;
padding: 6px;
font-weight: bold;
}
.mapContainer {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
}
js:
import React from 'react';
import ReactDOM from 'react-dom';
import mapboxgl from 'mapbox-gl';
mapboxgl.accessToken = 'MAPBOX_ACCESS_TOKEN';
class Application extends React.Component {
constructor(props) {
super(props);
this.state = {
lng: 5,
lat: 34,
zoom: 2
};
}
componentDidMount() {
const map = new mapboxgl.Map({
container: this.mapContainer,
style: 'mapbox://styles/mapbox/streets-v11',
center: [this.state.lng, this.state.lat],
zoom: this.state.zoom
});
map.on('move', () => {
this.setState({
lng: map.getCenter().lng.toFixed(4),
lat: map.getCenter().lat.toFixed(4),
zoom: map.getZoom().toFixed(2)
});
});
}
render() {
return (
<div>
<div className='sidebarStyle'>
<div>Longitude: {this.state.lng} | Latitude: {this.state.lat} | Zoom: {this.state.zoom}</div>
</div>
<div ref={el => this.mapContainer = el} className='mapContainer' />
</div>
)
}
}
ReactDOM.render(<Application />, document.getElementById('app'));

Related

Apply CSS transition to styled-component when React state changes

I have some state that changes after button click. The state changes the size of a sidebar.
Here is my CSS made with styled-components and conditional rendering:
const SidebarStyled = styled.div`
width: ${this.state.sidebarOpen ? '200px' : '70px'};
position: fixed;
left: 0px;
top: 0px;
height: 100vh;
background-color: #0c1635;
display: flex;
flex-direction: column;
`;
Any idea how I can apply a transition 0.2s on the conditional rendering?
I have tried to add transition: all 0.2s ease-in-out; and it didn't work.
As I mentioned in my comment, you need to pass in a prop and interpolate it out to change your CSS. Otherwise your component will re-render, and the CSS transition won't be applied.
const { React, ReactDOM, styled } = window;
class WontWork extends React.Component {
constructor(props) {
super(props);
this.state = { sidebarOpen: false };
}
render() {
const Sidebar = styled.div`
width: ${this.state.sidebarOpen ? "200px" : "70px"};
height: 20px;
background: red;
transition: width 1s;
`;
return (
<main>
<p>This won't work:</p>
<Sidebar />
<button
onClick={() => this.setState({ sidebarOpen: !this.state.sidebarOpen })}
>
Expand
</button>
</main>
);
}
}
const WorkingSidebar = styled.div`
width: ${(props) => (props.open ? "200px" : "70px")};
height: 20px;
background: green;
transition: width 1s;
`;
class WillWork extends React.Component {
constructor(props) {
super(props);
this.state = { sidebarOpen: false };
}
render() {
return (
<main>
<p>You need to pass in a <b>prop</b> to a predefined styled-component:</p>
<WorkingSidebar open={this.state.sidebarOpen} />
<button
onClick={() => this.setState({ sidebarOpen: !this.state.sidebarOpen })}
>
Expand
</button>
</main>
);
}
}
ReactDOM.render(
<div>
<WontWork />
<hr />
<WillWork />
</div>,
document.getElementById("app")
);
<script crossorigin src="https://unpkg.com/react#16.14.0/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16.14.0/umd/react-dom.development.js"></script>
<script crossorigin src="https://unpkg.com/react-is#16.13.1/umd/react-is.production.min.js"></script>
<script crossorigin src="https://unpkg.com/styled-components#5.3.3/dist/styled-components.min.js"></script>
<div id="app"></div>
Try this:
You can passe sidebarOpen as props:
<SidebarStyle sidebarOpen = {this.state.sidebarOpen}>
Then:
const sidebarStyle = styled.div`
width: 70px;
transition: transform .2s ease-in-out;
transform: ${props.sidebarOpen ? "scaleX(3)" : "scaleX(1)"};
.
.
.
`
I helped from here:
See here: Adding transitions to styled components
Does it work In this case?
Add a transition property like: transition:all 200ms ease-in;

React Leaflet Map won't proper render

Update: I couldn't solve the css issue. A friend recommended to me Mapbox and I have subsequently swaped the map. I'm so happy now.
Good evening community, my map appears only a bit. When I move the map by hand everything will be ok afterwards. I followed all instructions form https://react-leaflet.js.org/ and tried several solutions from the net, but can't solve it. Hope someone of you can give me the final hint, why I'm stuck.
incomplete map
// 1. App.js
// 2. Body.js
// App.js
import React, { useState, useEffect } from "react";
import axios from "axios";
import Spinner from "react-bootstrap/Spinner";
import "./normalize.css";
import "./App.css";
import Body from "./components/Body";
import Card from "./components/Card"
function App() {
const [geoPosition, setGeoPosition] = useState(null);
const [extraCountryInfo, setExtraCountryInfo] = useState(null);
const [spinnerEnabled, setSpinnerEnabled] = useState(false);
const [myLocationData, setMyLocationData] = useState(null);
useEffect(() => {
const fetchLocationInfo = async () => {
console.log("test");
let getCurrentCountry = "";
setSpinnerEnabled(true);
try {
const { REACT_APP_API_KEY } = process.env;
const getMyLocation = await axios(
`https://geo.ipify.org/api/v1?apiKey=${REACT_APP_API_KEY}`
);
getCurrentCountry = getMyLocation.data.location.country;
setMyLocationData(getMyLocation);
setGeoPosition(getMyLocation.data.location);
} catch (error) {
console.log(error.message);
}
try {
const getExtraCountryData = await axios(
`https://restcountries.eu/rest/v2/name/${getCurrentCountry}?fullText=true`
);
setExtraCountryInfo(getExtraCountryData);
} catch (error) {
console.log(error.message);
}
setSpinnerEnabled(false);
};
fetchLocationInfo();
}, []);
return (
<div className="App">
<div id="wrapper">
{extraCountryInfo && myLocationData && (
<Card
extraCountryInfo={extraCountryInfo}
myLocationData={myLocationData}
geoPosition={geoPosition}
setGeoPosition={setGeoPosition}
></Card>
)}
{spinnerEnabled && <Spinner animation="border" />}
{geoPosition && <Body geoPosition={geoPosition} />}
</div>
</div>
);
}
export default App;
//Body.js
import React from "react";
import { MapContainer,TileLayer, Marker, Popup } from "react-leaflet";
import './Body.css'
export default function Body(props) {
// console.log(props)
return (
<div id="mapid">
<MapContainer
center={[props.geoPosition.lat, props.geoPosition.lng]}
zoom={13}
scrollWheelZoom={true}
>
{console.log("re render",props.geoPosition.lat, props.geoPosition.lng)}
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[props.geoPosition.lat, props.geoPosition.lng]}>
<Popup>
Your are here
</Popup>
</Marker>
</MapContainer>
</div>
);
}
/* 1. App.css */
/* 2. Body.css */
/* App.css */
ul{
list-style: none;
}
li{line-height: 1.5rem;}
.App {
background-image: url("./assets/XT205511.JPG");
background-position: center;
background-repeat: no-repeat;
background-size:cover;
display: flex;
justify-Content: center;
align-items: center;
align-content: center;
font-family: 'Nunito', sans-serif;
background-color:lightblue;
}
#wrapper {
height: 80%;
}
/* Body.css */
#mapid {
width: 100%;
height: 40%;
/* width: 40rem;
height: 20rem; */
border: 2px rgb(241, 241, 243) solid;
border-radius: 1%;
margin-top: 0.5rem;
}
.leaflet-container {
/* width: 100%; */
height: 100%;
}
<!-- index.html -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""/>
<!-- Make sure you put this AFTER Leaflet's CSS -->
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""></script>

My Google Maps is not taking my footer CSS

I am trying to make sure that any CSS I put within my Footer is not affected by adding my Google Maps API. You can see from the example that I am not able to keep the back ground black.
Footer
import React, {Component} from 'react';
import { Map, Marker, GoogleApiWrapper } from 'google-maps-react';
import './App.css';
class Footer extends Component {
render(){
const style = {
width: '300px',
height: '300px',
backgroundColor: 'black'
}
return (
<div className="site-footer">
<footer>
<p>My Footer</p>
<Map
google={this.props.google}
zoom={10}
initialCenter={{
lat: 35.5496939,
lng: -120.7060049
}}
style={style}
/>
</footer>
</div>
)
}
}
export default GoogleApiWrapper({
apiKey: ('YOUR_API_KEY')
})(Footer);
Footer CSS
.site-footer {
left: 0;
bottom: 0;
width: 100%;
margin-top: 20px;
color: white;
text-align: center;
flex-shrink: 0;
background: black;
}
Footer Example
It seems that there are different divs that contains the map when using the google-maps-react library. Per the package's documentation there's a style - which you configure to set the map dimension and there's a containerStyle - which is a div that contains the map.
So to set the map background to black, you need to use the containerStyle.
class Footer extends Component {
render(){
const style = {
width: '300px',
height: '300px'
}
const containerStyle = {
position: 'absolute',
width: '100%',
height: '100%',
backgroundColor: 'black'
}
return (
<div className="site-footer">
<footer>
<p>My Footer</p>
<Map
google={this.props.google}
zoom={10}
initialCenter={{
lat: 35.5496939,
lng: -120.7060049
}}
style={style}
containerStyle={containerStyle}
/>
</footer>
</div>
)
}
}
export default GoogleApiWrapper({
apiKey: "YOUR_API_KEY"
})(Footer);
You would also need to define the width and height of your site-footer class to fill in the white spaces. I used 800px here so that it will really fully contain my map and its container.
.site-footer {
left: 0;
bottom: 0;
width: 800px;
height: 800px;
margin-top: 20px;
color: white;
text-align: center;
flex-shrink: 0;
background-color: black;
}
Please see sample code.
Please use your API key in the sample code for it to work.

React: Get element size in componentDidMount

I'm trying to implement the solution provided in this answer.
In the second step, I need to get the size of a div defined in my component in my component's componentDidMount. Many threads on StackOverflow have proposed using refs for this purpose. However, I have difficulty understanding how to implement it. Would you please give me a piece of code as an example to learn how to get the element's size after it is mounted in componentDidMount?
You can create a ref with createRef and store it in an instance variable which you pass to the ref prop of the element you want a reference to.
This ref will then have a reference to the node in the current property after the component has mounted.
Example
class App extends React.Component {
ref = React.createRef();
componentDidMount() {
const { current } = this.ref;
console.log(`${current.offsetWidth}, ${current.offsetHeight}`);
}
render() {
return <div ref={this.ref} style={{ width: 200, height: 200 }} />;
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
By creating a ref you have access to all element's properties like offsetWidth.
https://developer.mozilla.org/en-US/docs/Web/API/Element
class TodoApp extends React.Component {
constructor(props) {
super(props)
this.state = {
items: [
{ text: "Learn JavaScript" },
{ text: "Learn React" },
{ text: "Play around in JSFiddle" },
{ text: "Build something awesome" }
]
}
this.myRef = React.createRef();
}
componentDidMount() {
console.log(this.myRef.current.offsetWidth);
}
render() {
return (
<div ref={this.myRef}>
{this.state.items.map((item, key) => (
<div className="rootContainer" key={key}>
<div className="item">{item.text}</div>
</div>
))}
</div>
)
}
}
ReactDOM.render(<TodoApp />, document.querySelector("#app"))
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
.rootContainer {
display: inline-block;
}
.item {
display: inline-block;
width: auto;
height: 100px;
background: red;
border: 1px solid green;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="app"></div>

React this.props not working as expected

I am in the process of learning React and trying a sample code from a book. The code is simple it is supposed to display vowels in different colors defined in the ReactDOM.render but instead it displays them all in one color coming from the style tag.
Attached below is the code
<!DOCTYPE html>
<html>
<head>
<meta charset-="utf-8'">
<title>Styling in React</title>
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
<style>
#container {
padding: 50px;
background-color: #FFF;
}
div div div {
padding: 10px;
margin: 10px;
background-color: #ffde00;
color: #333;
display: inline-block;
font-family: monospace;
font-size: 32px;
text-align: center;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
var destination = document.querySelector("#container");
class Letter extends React.Component {
render() {
var letterStyle = {
padding:10,
margin:10,
backgroundColor:this.props.bgcolor,
color:"#333",
display:"inline-block",
fontFamily:"monospace",
fontSize:32,
textAlign:"center"
};
return (
<div>
{this.props.children}
</div>
);
}
}
ReactDOM.render(
<div>
<Letter bgcolor="#58B3FF">A</Letter>
<Letter bgcolor="#FF605F">E</Letter>
<Letter bgcolor="#FFD52E">I</Letter>
<Letter bgcolor="#49DD8E">O</Letter>
<Letter bgcolor="#AE99FF">U</Letter>
</div>,
destination
);
</script>
</body>
</html>
}
It looks like you aren't using letterStyle anywhere. Try the following:
render() {
var letterStyle = {
padding:10,
margin:10,
backgroundColor:this.props.bgcolor,
color:"#333",
display:"inline-block",
fontFamily:"monospace",
fontSize:32,
textAlign:"center"
};
return (
<div style={letterStyle}>
{this.props.children}
</div>
);
}
Try {this.props.bgcolor} you need a {} to use dynamic variables.

Resources