让我知道这是否不合适。
我目前正在使用带有不同标记(最多1000个)的地图构建一个React应用,每个地图都有其特定性。用户可以设置不同的过滤器,应用程序应显示相关的过滤器。我目前有一种有效的算法,但我敢肯定,我们可以提高它的效率,减少资源消耗。
这是我要讲的代码:
将仅显示重要内容。
要解释渲染,我有一个地图,其中显示了所有标记,下面有所有过滤器的列表,用户可以单击以应用该过滤器。
谢谢您的贡献!
class SomeComponent extends Component {
state = {
allMarkers: [
{id: "1", filter: ['weekout', 'restaurant'], latlng: {latitude: 37.78825, longitude: -122.4224},title:'42'},
{id: "2", filter: ['weekout'], latlng: {latitude: 37.78814, longitude: -122.4314},title:'Taverne du mont belon'},
{id: "3", filter: ['restaurant', 'party'], latlng: {latitude: 37.78825, longitude: -122.1224},title:'Chez Lapin'},
{id: "4", filter: ['party'], latlng: {latitude: 37.78825, longitude: -122.3324},title:'Pizza toto'},
// up to 1000
],
filteredMarkers: [
],
filters: [
{id: "1", selected: true, text: 'filter', filter: 'weekout'},
{id: "2", selected: true, text: 'filter', filter:'pin'},
{id: "3", selected: true, text: 'filter', filter: 'party'},
{id: "4", selected: true, text: 'filter', filter: 'restaurant'},
{id: "5", selected: false, text: 'filter', filter: 'beer'},
{id: "6", selected: true, text: 'filter', filter:'love'},
{id: "7", selected: false, text: 'filter', filter:'yum'},
],
}
filterMarkers() {
let activefilters = this.state.filters.map((item) => item.selected && item.filter);
let markers = this.state.allMarkers;
let filteredmarkers = markers.map((item) => activefilters
.some(r => item.filter.includes(r)) && item)
.filter((item) => item)
this.setState({...this.state, filteredMarkers: filteredmarkers})
}
selectedFilter(id) {
let selectedfilters = this.state.filters
selectedfilters.map((filter) => filter.id == id ? filter.selected = !filter.selected : null)
this.setState({...this.state, filters: selectedfilters})
this.filterMarkers();
}
render() {
return(
<View>
<MapView >
{this.state.filteredMarkers.map((marker, idx) => (
<Marker
key={idx}
identifier={marker.id}
coordinate={marker.latlng}
/>
))}
</MapView>
<FlatList
data={this.state.filters}
renderItem={({item, idx}) =>
<TouchableOpacity onPress={() => this.selectedFilter(item.id)}>
<View >
<Image source={item.img} idx={idx}/>
</View>
</TouchableOpacity>
}
/>
</View>
)
}
}
答案 0 :(得分:1)
每当您尝试进行任何类型的优化时,通常都会在速度和内存之间进行权衡。但是首先,让我们分析一下您当前的方法:
// don't need to worry here as your filter set is small
let activefilters = this.state.filters.map((item) => item.selected && item.filter)
let markers = this.state.allMarkers
let filteredmarkers = markers
// will run totalMarkers * activeFilters * filtersPerMarker
.map((item) =>
activefilters.some(r => item.filter.includes(r)) && item
)
// will run totalMarkers
.filter((item) => item)
因此,由于您只有几个过滤器,因此,如果要增加更多的标记,则性能应该或多或少地线性增加,这很好。这意味着做口罩之类的事情只会使您获得很小的性能提升。
如果您真的想优化它,那么您将以O(1)为目标,可以通过缓存来实现。为此,您基本上以一种可以执行即时查找的方式来重组数据。如果您的标记是静态的,那很好,但是如果您经常添加和删除标记(或更改其各自的过滤器),则必须制定一种策略来重新缓存数据。您可以执行以下操作:
// run this once, and update when markers are added/removed or marker filters change
const cache = {}
state.allMarkers.forEach(marker => {
const id = marker.filter.join('-')
if(!cache[id]){ cache[id] = [] }
cache[id].push(marker)
})
现在要获取过滤结果,您只需查找具有修改后ID的缓存即可。
const filterId = this.state.filters
.filter(item => item.selected)
.map(item => item.filter)
.join('-')
const filteredMarkers = cache[filterId] || []
可能有更好的方法来处理id,但希望您能理解。
这里的要点在于,它取决于用户与数据的交互方式以及您拥有的数据量。再说一遍,1000足够小,不会引起您算法选择上的任何差异,除了做一个简单的过滤器(如您正在使用的过滤器)以外,要做的任何事情都会不必要地使事情复杂化。任何性能问题也更有可能来自渲染大型集合,而不是组织大型集合。
因此,换句话说,编写最简单,最易读的代码,并且只有在确实有充分理由的情况下才进行优化(即,即使有一个基准,也已经确定并确定了实际瓶颈)。花更多的时间使您的应用程序拥有美好的体验!