我对 React 和 Web 开发很陌生,所以希望这是有意义的。所以我正在构建一个应用程序,它使用谷歌地图api和React来显示我从Foursquare获取的地方的标记。
我从 Foursquare 生成一个地点数组(仅限于 5 个我想保持静态的地方(,并将其放置在我的应用程序状态中,以便我可以将数据传递到列表侧边栏和我的地图以生成标记。我还创建了一个过滤器搜索栏,我想用它来过滤列表和地图标记,以便只有列表中的地点和地图标记与用户的搜索输入匹配。
我设法过滤了列表,但我正在努力找到一种过滤地图标记的方法。
现在我想我需要将我的位置数组移出状态并使用搜索输入来过滤并创建一个我保留在该状态中的新数组,但我不确定如何做到这一点......这是我到目前为止所做的:
过滤器.js
import React, { Component } from 'react';
class Filter extends Component {
filterUpdate() {
const val = this.myValue.value
this.props.filterUpdate(val)
}
render() {
return(
<header>
<form>
<input
type='text'
ref={ (value) => { this.myValue = value } }
placeholder='Type to filter...'
onChange={this.filterUpdate.bind(this)}
/>
</form>
</header>
)
}
}
export default Filter;
列表.js
import React, { Component } from 'react';
class List extends Component {
render() {
const { places, filterText } = this.props;
const placeList = places
/*.filter(place => {
// remove places that do not match current filter text
return place.venue.name.toLowerCase().indexOf(filterText.toLowerCase()) >= 0
})
*/
.map(place => {
return (
<li key={place.venue.id}>
<p>{place.venue.name}</p>
<p>{place.venue.location.address}</p>
</li>
)
})
return(
<div className="list">
<ul>
{placeList}
</ul>
</div>
)
}
}
export default List;
地图.js
import React, { Component } from 'react'
class Map extends Component {
componentDidMount() {
this.loadMap();
}
loadMap = () => {
loadScript("https://maps.googleapis.com/maps/api/js?key=<INSERT API HERE>=initMap");
window.initMap = this.initMap;
// Shows alert when problem with auth, from: https://developers.google.com/maps/documentation/javascript/events#auth-errors
window.gm_authFailure = function() {
alert('Cannot load Google Maps! Please ensure that you have a valid Google Maps API key! Please go to https://developers.google.com/maps/documentation/javascript/get-api-key')
}
}
initMap = () => {
let map = new window.google.maps.Map(document.getElementById('map'), {
center: {lat: 52.637106, lng: -1.139771},
zoom: 15
});
this.props.places.map(place => {
const marker = new window.google.maps.Marker({
position: {lat: place.venue.location.lat, lng: place.venue.location.lng},
map: map,
title: place.venue.name,
animation: window.google.maps.Animation.DROP,
id: place.venue.id
});
});
}
render() {
return(
<div id="map"></div>
)
}
}
export default Map;
function loadScript(url) {
// https://stackoverflow.com/questions/34779489/rendering-a-google-map-without-react-google-map
let ref = window.document.getElementsByTagName('script')[0];
let script = window.document.createElement('script');
script.src = url;
script.async = true;
script.defer = true;
ref.parentNode.insertBefore(script, ref);
script.onerror = function () {
document.write('Load error: Google Maps')
};
}
应用.js
import React, { Component } from 'react'
import Filter from './components/Filter'
import List from './components/List'
import Map from './components/Map'
import axios from 'axios'
class App extends Component {
constructor(props) {
super(props)
this.state = {
filterText: '',
places: []
}
}
filterUpdate(value) {
this.setState({
filterText: value
})
}
componentDidMount() {
this.loadPlaces()
}
loadPlaces = () => {
const endPoint = "https://api.foursquare.com/v2/venues/explore?";
const parameters = {
client_id: "<INSERT API HERE>",
client_secret: "5A3ANB4RL11MWKHBA2W0KYGKDIRHERLL1XRZE3JEH1BUS4V5",
v: "20180323",
query: "coffee",
near: "Leicester, UK",
limit: 5
}
// Get data for coffee places from Foursquare
axios.get(endPoint + new URLSearchParams(parameters))
.then(response => {
this.setState({
places: response.data.response.groups[0].items
})
})
.catch(error => {
alert("An error occurred fetching data from Foursquare: " + error);
})
}
render() {
const { places, filterText } = this.state;
const filterPlaces = places
.filter(place => {
return place.venue.name.toLowerCase().indexOf(filterText.toLowerCase()) >= 0
})
return (
<div className="App">
<Filter
filterText={this.state.filterText}
filterUpdate={this.filterUpdate.bind(this)}
/>
<main>
<List
places={filterPlaces}
filterText={this.state.filterText}
/>
<Map
places={filterPlaces}
/>
</main>
</div>
);
}
}
export default App;
索引.css
body {
height: 100%;
margin: 0;
padding: 0;
font-family: sans-serif;
}
#map {
height: 100vh;
}
.list {
background-color: #fff;
opacity: 0.9;
z-index: 1;
text-align: left;
margin: 5px;
width: 25%;
position: absolute;
padding: 5px;
min-width: 120px;
height: 400px;
overflow-y: scroll;
top: 200px;
}
/* ##### Search ##### */
header {
background: #3498db;
}
input[type='text'] {
margin: 1rem;
background: #fff;
font-size: 1.3rem;
border: none;
box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.3);
border-radius: 3px;
padding: 0 2rem;
width: calc(100% - 3rem);
height: 4rem;
}
我认为我无法从渲染方法更新状态...我甚至可以过滤处于该状态的数组以更改显示的标记吗?帮助!
一些想法
在组件 (this.map=map
( 实例中保存对map
(initMap( 的引用。
shouldComponentUpdate
将在过滤器更改时调用(使用新道具(。
使用保存的地图引用应该可以删除所有现有标记。从新道具中,您可以创建新标记。可以优化此过程,即仅隐藏过滤掉的标记。
当然(像在 sCU 中一样(将this.props
与nextProps
进行比较,以避免在地图上进行不必要的操作。
在 sCU 结束时返回 false 以阻止重新渲染 - 没有带有映射的div 将被渲染清除。