问题
I am new to react-leaflet. Need little help to fix my issue. Follow up with Previous post
I have textfield which filter data. I was able to filter data in the table but not able to filter the data in the map. For example: if I search for name: 'VaiBike' it should show in table and marker in the map. Note: only show the data which is filter in map as well as in the table. so does for the other data.
How can I change my code so that I can show marker and data in table at the same time.
Running code
import React, { Component } from 'react'
import { Map, TileLayer, Marker, Popup } from 'react-leaflet'
import './style.css'
import 'leaflet/dist/leaflet.css'
import L from 'leaflet'
import icon from 'leaflet/dist/images/marker-icon.png'
import iconShadow from 'leaflet/dist/images/marker-shadow.png'
import TextField from '@material-ui/core/TextField'
// Import React Table
import ReactTable from 'react-table'
import 'react-table/react-table.css'
import matchSorter from 'match-sorter'
var myIcon = L.icon({
iconUrl:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAFgUlEQVR4Aa1XA5BjWRTN2oW17d3YaZtr2962HUzbDNpjszW24mRt28p47v7zq/bXZtrp/lWnXr337j3nPCe85NcypgSFdugCpW5YoDAMRaIMqRi6aKq5E3YqDQO3qAwjVWrD8Ncq/RBpykd8oZUb/kaJutow8r1aP9II0WmLKLIsJyv1w/kqw9Ch2MYdB++12Onxee/QMwvf4/Dk/Lfp/i4nxTXtOoQ4pW5Aj7wpici1A9erdAN2OH64x8OSP9j3Ft3b7aWkTg/Fm91siTra0f9on5sQr9INejH6CUUUpavjFNq1B+Oadhxmnfa8RfEmN8VNAsQhPqF55xHkMzz3jSmChWU6f7/XZKNH+9+hBLOHYozuKQPxyMPUKkrX/K0uWnfFaJGS1QPRtZsOPtr3NsW0uyh6NNCOkU3Yz+bXbT3I8G3xE5EXLXtCXbbqwCO9zPQYPRTZ5vIDXD7U+w7rFDEoUUf7ibHIR4y6bLVPXrz8JVZEql13trxwue/uDivd3fkWRbS6/IA2bID4uk0UpF1N8qLlbBlXs4Ee7HLTfV1j54APvODnSfOWBqtKVvjgLKzF5YdEk5ewRkGlK0i33Eofffc7HT56jD7/6U+qH3Cx7SBLNntH5YIPvODnyfIXZYRVDPqgHtLs5ABHD3YzLuespb7t79FY34DjMwrVrcTuwlT55YMPvOBnRrJ4VXTdNnYug5ucHLBjEpt30701A3Ts+HEa73u6dT3FNWwflY86eMHPk+Yu+i6pzUpRrW7SNDg5JHR4KapmM5Wv2E8Tfcb1HoqqHMHU+uWDD7zg54mz5/2BSnizi9T1Dg4QQXLToGNCkb6tb1NU+QAlGr1++eADrzhn/u8Q2YZhQVlZ5+CAOtqfbhmaUCS1ezNFVm2imDbPmPng5wmz+gwh+oHDce0eUtQ6OGDIyR0uUhUsoO3vfDmmgOezH0mZN59x7MBi++WDL1g/eEiU3avlidO671bkLfwbw5XV2P8Pzo0ydy4t2/0eu33xYSOMOD8hTf4CrBtGMSoXfPLchX+J0ruSePw3LZeK0juPJbYzrhkH0io7B3k164hiGvawhOKMLkrQLyVpZg8rHFW7E2uHOL888IBPlNZ1FPzstSJM694fWr6RwpvcJK60+0HCILTBzZLFNdtAzJaohze60T8qBzyh5ZuOg5e7uwQppofEmf2++DYvmySqGBuKaicF1blQjhuHdvCIMvp8whTTfZzI7RldpwtSzL+F1+wkdZ2TBOW2gIF88PBTzD/gpeREAMEbxnJcaJHNHrpzji0gQCS6hdkEeYt9DF/2qPcEC8RM28Hwmr3sdNyht00byAut2k3gufWNtgtOEOFGUwcXWNDbdNbpgBGxEvKkOQsxivJx33iow0Vw5S6SVTrpVq11ysA2Rp7gTfPfktc6zhtXBBC+adRLshf6sG2RfHPZ5EAc4sVZ83yCN00Fk/4kggu40ZTvIEm5g24qtU4KjBrx/BTTH8ifVASAG7gKrnWxJDcU7x8X6Ecczhm3o6YicvsLXWfh3Ch1W0k8x0nXF+0fFxgt4phz8QvypiwCCFKMqXCnqXExjq10beH+UUA7+nG6mdG/Pu0f3LgFcGrl2s0kNNjpmoJ9o4B29CMO8dMT4Q5ox8uitF6fqsrJOr8qnwNbRzv6hSnG5wP+64C7h9lp30hKNtKdWjtdkbuPA19nJ7Tz3zR/ibgARbhb4AlhavcBebmTHcFl2fvYEnW0ox9xMxKBS8btJ+KiEbq9zA4RthQXDhPa0T9TEe69gWupwc6uBUphquXgf+/FrIjweHQS4/pduMe5ERUMHUd9xv8ZR98CxkS4F2n3EUrUZ10EYNw7BWm9x1GiPssi3GgiGRDKWRYZfXlON+dfNbM+GgIwYdwAAAAASUVORK5CYII=',
iconSize: [25, 41],
iconAnchor: [12.5, 41],
popupAnchor: [0, -41],
})
let DefaultIcon = L.icon({
iconUrl: icon,
shadowUrl: iconShadow,
})
L.Marker.prototype.options.icon = DefaultIcon
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
location: {
lat: 51.505,
lng: -0.09,
filterAll: '',
},
bikeData: [],
haveUsersLocation: false,
zoom: 3,
}
}
//lifecycle method to get the bike information
componentDidMount() {
fetch('https://api.citybik.es/v2/networks')
.catch(error => {
console.log(error)
})
.then(res => res.json())
.then(response => {
const networkData = response.networks
this.setState({
bikeData: networkData,
})
})
}
filterAll = e => {
const { value } = e.target
const filterAll = value
const filtered = [{ id: 'all', value: filterAll }]
const filterdMap =[{id:'bikeData', value: filterAll}]
this.setState({ filterAll, filtered ,filterdMap})
}
render() {
const position = [this.state.location.lat, this.state.location.lng]
const bikeData = this.state.bikeData
return (
<div
style={{
height: '100vh',
}}
id="map"
>
<div align="right">
<form noValidate autoComplete="off">
<TextField
id="row"
label="Search Bike"
margin="normal"
value={this.state.filterAll}
onChange={this.filterAll}
/>
</form>
</div>
<Map className="map" center={position} zoom={this.state.zoom}>
<TileLayer
attribution="&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{bikeData &&
bikeData.map(data => {
console.log(data)
return (
<Marker
icon={myIcon}
key={data.id}
position={[data.location.latitude, data.location.longitude]}
>
<Popup>
Name: {data.name} <br />
Station Details:{' '}
{[data.location.city, data.location.country]}
</Popup>
</Marker>
)
})}
</Map>
<div>
<ReactTable
filtered={this.state.filtered}
defaultFilterMethod={(filter, row) =>
String(row[filter.id]) === filter.value
}
data={bikeData}
columns={[
{
columns: [
{
Header: ' Name',
accessor: 'name',
filterAll: true,
},
{
Header: '',
id: 'all',
width: 0,
resizable: false,
sortable: false,
Filter: () => {},
getProps: () => {
return {}
},
filterMethod: (filter, rows) => {
const result = matchSorter(rows, filter.value, {
keys: ['name'],
threshold: matchSorter.rankings.WORD_STARTS_WITH,
})
return result
},
filterAll: true,
},
],
},
]}
defaultPageSize={10}
/>
<br />
</div>
</div>
)
}
}
Help with running code highly appreciated. Thanks in advance.
回答1:
If I understand your question correctly, you'll need to make a few adjustments to your code. First, add state to track the "filtered bike data" (ie the data that is visible to users in the UI). You can do so by adding something like this in your constructor:
constructor(props) {
super(props)
this.state = {
location: {
lat: 51.505,
lng: -0.09,
filterAll: '',
},
bikeData: [],
filteredBikeData : [], // Add this
haveUsersLocation: false,
zoom: 3,
}
}
Now, in you filterAll
all text field change handler, you'll want to update the filteredBikeData
state based on the current field value. You can do so with something as follows:
filterAll = e => {
const { value } = e.target
// Get a filtered list of bikes based on original list
const filteredBikes = this.state.bikeData.filter(bike => {
// Filter bikes by name. Use toLowerCase to avoid case sensitivity issues
return bike.name.toLowerCase().indexOf(value.toLowerCase()) !== -1
})
const filterAll = value
const filtered = [{ id: 'all', value: filterAll }]
const filterdMap =[{id:'bikeData', value: filterAll}]
// Update state to include filtered bikes array
this.setState({ filterAll, filtered ,filterdMap, filteredBikes})
}
Finally, you'll want to render markers based on the filtered array of bikes - update your render method like so:
{ /* use filteredBikes instead of bikes */
{ this.state.filteredBikes && this.state.filteredBikes.map(data => {
console.log(data)
return (
<Marker
icon={myIcon}
key={data.id}
position={[data.location.latitude, data.location.longitude]}
>
<Popup>
Name: {data.name} <br />
Station Details:{' '}
{[data.location.city, data.location.country]}
</Popup>
</Marker>
)
})}
As an extra, you might also want to default the value of filteredBikes
to the response that you get from the server, so that the user initially sees something on screen:
componentDidMount() {
fetch('https://api.citybik.es/v2/networks')
.catch(error => {
console.log(error)
})
.then(res => res.json())
.then(response => {
const networkData = response.networks
this.setState({
bikeData: networkData,
filteredBikeData : networkData // Add this
})
})
}
来源:https://stackoverflow.com/questions/52637614/filter-react-table-and-react-leaflet-marker-at-the-same-time-using-textfield-sh