How do I send the state(data) of info
to the App hook, so that I can display the properties in divs? setInfo(info)
stores the data I want to display on the Map hook and I can see all the properties when I console.log(info)
in _onClick
. I am stuck on how to use and show it in App. Thanks for the help.
App
const App = () => {
return (
<div className="App">
<div className="inner-left map-container">
<Map />
</div>
<div className="inner-right info-container">
<Nav />
<Search />
<div id="info_side">
{info} // throws an error undefined
</div>
</div>
</div>
);
}
export default App;
Map
const Map = () => {
...
const [info, setInfo] = useState(null)
...
const _onClick = event => {
const { features } = event;
const info = features && features.find(f => f.layer.id === 'icon');
setInfo(info); // This is what I would like to use in App
}
return (
<ReactMapGL
{...viewport}
onViewportChange={_updateViewport}
width="100%"
height="100%"
mapStyle={mapStyle}
mapboxApiAccessToken={TOKEN}
onHover={_onHover}
onClick={_onClick}>
<Source id="my-data" type="geojson" data={geojson}>
<Layer {...icon} />
</Source>
<div style={navStyle}>
<NavigationControl onViewportChange={_updateViewport} />
...
</div>
</ReactMapGL>
);
}
export default Map;
You can pass a callback prop to the child.
App
const App = () => {
const [info, setInfo] = useState(); // local info state
const displayInfo = () => {
// this is where I would hope to return the <div>'s with data such as <div>info.Company</div>
// access current copy of info
}
return (
<div className="App">
<div className="inner-left map-container">
<Map onInfoChange={setInfo} /> // pass info state setter to child
</div>
<div className="inner-right info-container">
<Nav />
<Search />
<div id="info_side">
{displayInfo}
</div>
</div>
</div>
);
}
export default App;
Map
const Map = ({
onInfoChange, // passed callback prop
}) => {
...
const [info, setInfo] = useState(null)
// use an effect hook to call callback whenever info updates
useEffect(() => {
onInfoChange(info); // pass info back to parent
}, [info]);
const _onClick = event => {
const { features } = event;
const info = features && features.find(f => f.layer.id === 'icon');
setInfo(info); // This is what I would like to use in App
}
return (
<ReactMapGL
{...viewport}
onViewportChange={_updateViewport}
width="100%"
height="100%"
mapStyle={mapStyle}
mapboxApiAccessToken={TOKEN}
onHover={_onHover}
onClick={_onClick}>
<Source id="my-data" type="geojson" data={geojson}>
<Layer {...icon} />
</Source>
<div style={navStyle}>
<NavigationControl onViewportChange={_updateViewport} />
...
</div>
</ReactMapGL>
);
}
export default Map;
At this point I should point out that you now have duplicate state stored in two components so it's a great idea to hoist the info state and logic to the closest common ancestor (App) and simply pass the info as a prop to the component that needs it (Map). Single source of truth principle. Or as other have pointed out, switch to a global state management system, like redux, or roll your own using React Context (i.e. what react-redux is using under the hood).