04-HK custom city selection list
This article is hkzf The series of mobile tutorials aims to help beginners quickly master the project development based on React technology stack through a series of articles.
requirement analysis
The custom city list is divided into two parts. The left side is divided into three parts: current location, hot cities, and alphabetical list of cities in A,B,C,D. The left list scrolls, and the right index scrolls; the right index is clicked, and the left city list scrolls to the corresponding index. Click on the list and select the city.
Realization
Construct a list of required city data structures
[{"Current positioning":""},{"Hot cities":["Guangzhou","Beijing"..]},{A:[....]}]
getAllCities = async (params) => { //Current positioning City const { mapReducer } = store.getState(); const cityName = mapReducer.cityName; // Get all cities let allCities = (await axios.get("/area/city?level=1")).body; //Get hot cities const hotCities = (await axios.get("/area/hot")).body; let totalCity = [ { "Current positioning": [cityName] }, { "Hot cities": hotCities.map(v => v.label) } ]; // Think about it. All cities a: [...] //[{"current location": ""}, {"hot city": ["Guangzhou", "Beijing"..]}, {A: [...]}] //First, make a sort ab ac ad ba bb allCities = allCities.sort(function (a, b) { return a.short.localeCompare(b.short); }) //{A:[....],B:[....],C:[...]} allCities.forEach(v => { //Take the capitalization of the initial in the abbreviation let firstLetter = v.short[0].toUpperCase(); //Determine whether the initial has appeared in totalCity let index = totalCity.findIndex(item => { if (item[firstLetter]) { return true; } else { return false; } }) if (index === -1) { //For example, A [{},{"A":[v.label]}] was not found totalCity.push( { [firstLetter]: [v.label] } ); } else { totalCity[index][firstLetter].push(v.label) } }); let keyArr = totalCity.map(v => Object.keys(v)[0]); keyArr[0] = "#"; keyArr[1] = "heat"; this.setState({ totalCity, keyArr }) }
Rendering long lists using react virtualized
Install react virtualized
npm install react-virtualized
List of cities
<div className="list_content" > <AutoSizer> {({ height, width }) => ( <List ref={this.MainList} //Uncontrolled form height={height} rowCount={this.state.totalCity.length} rowHeight={this.rowHeight} rowRenderer={this.rowRenderer} onRowsRendered={this.onRowsRendered} width={width} scrollToAlignment="start" // Alignment, click the letter on the right if not added, the scrolling position of the list on the left is not correct /> )} </AutoSizer> </div>
Rendering the list of letters on the right
{/* Initials start */} <div className="key_list"> { this.state.keyArr.map( (v,i) => { return <div onClick={this.onKeyLetterClick.bind(this,i)} className={"key_item " + ( i===this.state.selectIndex ? "active":"")} key={v}> {v}</div> }) } </div> {/* End of acronym */}
Rendering and click events for each line
rowRenderer = ({ key, index, style }) => { //{"hot city": ["Guangzhou", "Shanghai"]} let item = this.state.totalCity[index]; let item_name = Object.keys(item)[0]; return ( <div key={key} style={style}> <div className="city_list_name"> {item_name} </div> <div className="city_list_content" > { item[item_name].map((v, i) => { return <div key={i} onClick={this.itemOnClick.bind(this, v)} className="list_item">{v}</div> }) } </div> </div> ); } itemOnClick = (v) => { store.dispatch(getCityNameAction(v)); window.history.go(-1); } rowHeight = ({ index }) => { let item = this.state.totalCity[index]; return (Object.values(item)[0].length + 1) * 40; } onKeyLetterClick = (index) => { this.MainList.current.scrollToRow(index); this.setState({ selectIndex:index }) } onRowsRendered = ({startIndex}) => { this.setState({ selectIndex:startIndex }) }