I am building a ReactJs application with react-leaflet.
Problem is that there are a lot of Leaflet plugins that has no support for react-leaflet.
I try to use this plugin
http://kartena.github.io/Leaflet.zoomslider/
Can somebody suggest a solution in this case?
Most Leaflet plugins don't have a React component. You can create custom components for React-Leaflet from the Leaflet plugin.
I was going to say you do it by getting a reference to the map object, but I don't think that's needed. But I have left that in at the base of this response as it a very helpful thing to know.
try the following:
var map = L.map('map', {
zoomsliderControl: true,
zoomControl: false,
layers: [layer]
}).setView([57.7, 11.9], 8);
Where 'map' is the id of the Map element.
===========================================
On your Map element get a reference to the map object.
<Map ref={(m) => this.leaf = m} etc...>
then in your react component.
where you have componentDidMount= () =>{
use the map object to add in the slider
var map = this.leaf.leafletElement;
Related
The code below is taken directly from arcgis via react on how to display a map.
If i wanted to say, zoom in to a set of coordinates, but the code for that was set in another component, how can i get that component to talk to the map here in this component?
import Map from '#arcgis/core/Map';
import MapView from '#arcgis/core/views/MapView';
const map = new Map({
basemap: "topo-vector"
});
const view = new MapView({
container: "viewDiv",
map: map
});
I resolved this by using redux toolkit to set the map as a global state object.
The entire map view is set in a useEffect, once i initialize each of the views, i dispatch the map view to a reducer in rtk.
dispatch(updateMapViewState(view));
updateMapViewState: (state, action) => {
state.view = action.payload
},
Then, when i want to use the map in a separate component, i do:
const view = useSelector((state) => state.MapSlice.view);
In this way, all components can access the map outside of the useEffect in the map component, and can manipulate it without creating a new map view. This worked for me. I assume you could probably do this with context api, but we aren't using that as a global state manager.
This may not be the recommended or best way to achieve this, but I had success by passing the view object from the map component back to the parent component, then saving it to the parent component's state.
// in App.js
saveViewToState(view){
this.setState({view: view})
}
<MapComponent saveViewToState={this.saveViewToState}/>
// in MapComponent.js
let view = new View()
this.props.saveViewToState(view)
Then I was able to interact with the view object from the parent:
// in App.js
this.state.view.extent = {xmin: 1, ymin: 1, xmax: 2, ymax: 2}
This doesn't work perfectly (for some reason I can't call view.goTo, but view.extent works). I'd be keen to hear if there is a better way to achieve this.
Still looking for a clear answer to this problem.
Have not found an example separating the map/view creation and adding layers into differing components.
I am using an Open Layers map inside React. I am attaching it to the DOM using setTarget like so:
const mapObject = useMap(maplayers);
useEffect(() => {
mapObject.setTarget(mapRef.current);
return () => mapObject && mapObject.setTarget(undefined);
},[mapObject]);
Inside the useMap.js hook I am writing changes to the center and zoom of the map back to the context:
const {
zoom,
setZoom,
center,
setCenter,
} = useContext(MapContext);
let mapObject = null;
var projection = new olProj.Projection({
code: 'EPSG:25832',
units: 'm',
});
let options = {
target: 'map',
controls: olControl.defaults({
rotate: false,
zoom: false,
attributionOptions: {
collapsible: false,
},
}),
layers: maplayers,
view: new ol.View({
projection: projection,
center: center,
zoom: zoom
}),
};
mapObject = new ol.Map(options);
mapObject.on('moveend', (e) => {
console.log('moveend');
setCenter(() => e.target.getView().getCenter());
setZoom(() => e.target.getView().getZoom());
});
The problem now is that the whole map gets rerendered every time the center and zoom change. How can I avoid this? The only idea I have is to use useEffect with a dependency array that misses center and zoom but I know this is bad practise and should not be done.
You just discovered why one should not use useEffect to create Openlayers components in React. I answer this question once per week here - I will probably end up writing a very long and detailed answer and then start marking those questions as duplicates. Or maybe write a tutorial for Openlayers + React.
What you are trying to achieve is not easy and no one got it right the first time. I am the author of rlayers - https://github.com/mmomtchev/rlayers - a set of components for using Openlayers in React. The only reliable way to do everything that React expects is to use class-based components and to completely rewrite the React component life-cycle. You are free to use my components - either directly, either as an inspiration for writing your own.
In your particular case, the problem is that you create a new mapObject every time the hook is called. React detects this change and decides that the component must be rerendered. Built-in React hooks work around this by memoizing the value. Your hook should declare the dependencies of the mapObject and then use React.useMemo to always return the same object:
const mapObject = React.useMemo(() => {
// code to generate the mapObject
return mapObject;
}, [ projection, url, /* and all other items that require rerender */ ]
);
This way your hook will always return the same mapObject and you will continue to use a useEffect with only the mapObject as a dependency - according to the React guidelines.
I am trying to render icons that are set in the back end for each service on the page. The data comes from an api and includes the correct names for the icons. I am importing the needed icons from react-icons before hand...
I tried it this way:
//Services and icons
var serviceICON = this.state.services.map(service => {
let Icon = service.Icon
return <tr><td><Icon /></td><td> {service.serviceName}</td></tr>
});
This almost works - the only problem is that the icons are not rendered. Instead the html looks like this:
<fabed></fabed>
I don't understand why this happens. The api delivers the correct name (=> FaBed), so why is this rendering as all lower case?
Thanks a lot for your help in advance!
Edit:
The complete array for one of the services would look like this:
id: 2
serviceName: "Hotel"
trip: 6
Icon: "FaBed"
created_at: "2020-07-08T06:45:02.239Z"
updated_at: "2020-07-22T07:52:05.066Z"
I am mapping through each of these and try to output the code above. As you can see "Icon" comes with the correct spelling. So I don't understand why it is rendered in all lower case...
Basically what is happening here is Icon is just a string so the react framework treats it differently.
html tags vs react components
<Icon />
is converted to
React.createElement(Icon, {});
Choosing the Type at Runtime
You'll notice here the key is using a map to match a string value with an actual React Component. For your case you'll need to map service.Icon to the relevant (imported) Icon Component.
import FaBed from '...';
...
const icons = {
...
"FaBed": FaBed,
...
};
...
var serviceICON = this.state.services.map(service => {
let Icon = icons[service.Icon];
return <tr><td><Icon /></td><td> {service.serviceName}</td></tr>
});
React responsiveness
I just wanted to know how the responsiveness in to the react is possible ?
There are different ways to achieve responsive like
css-grid bootstrap-grid react-bootstrap
could some let me know what is the preferred way to do the responsive into react?
Regards,
Just use plain JS, that's the beauty of React. I personally do this:
class Responsive extends Component {
state = { isMobile: false };
componentDidMount() {
// use css media quries
this.isMobile = window.matchMedia("(max-width: 767px)");
// test on first run
this.handleIsMobile({ matches: this.isMobile.matches });
// listen to changes after first run
this.isMobile.addListener(this.handleIsMobile);
}
componentWillUnmount() {
// stop listening when unmounted
this.isMobile.removeListener(this.handleIsMobile);
}
handleIsMobile = ({ matches }) => this.setState({ isMobile: matches });
render() {
if (this.state.isMobile) return <div>MOBILE</div>;
return <div>DESKTOP</div>;
}
}
First refer this, Bootstrap webpack
This is one way of using bootstrap in reactjs projects.
The advantage of this is that u get access to latest bootstrap css.
The disadvantage of using this is its complicated to use jquery plugins in reactjs. Hovewr if you are only interested in css, then its perfect.
Using this u can directly use bootstrap classes from documentation and get more control.
Just use className instead of class
If u want simple setup , then u can use reactstrap link
Other frameworks include react-bootstrap link
I am building a dashboard that links to various servers using ReactJS and electron. Now in a page I have a button and when it is clicked it renders a "webview" in the application using tag but i do not get the whole page as it needs some additional headers like langauge. I saw in the official documentation here https://electron.atom.io/docs/api/webview-tag/ that for using webview methods we first have to load the webview element but I tried all the possibilities that I had in my mind but couldnt come up with a solution.
Please if anyone can let me know where and how should I load the webview element and how to use the webview methods inside the component, really appreciated.
Thanks.
Keep the ref of webview and initially don't load any url
<WebView autosize={true} ref={(input) => { this.webview = input; }} src="data:text/plain" />
in your componentDidUpdate() load url with extra headers
if (this.webview) {
this.webview.loadUrl(url, {
extraHeaders: ""
});
}