#04-HK custom city selection list

Keywords: Front-end React axios Mobile npm

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
        })
    }
    

Posted by Cynix on Wed, 04 Dec 2019 19:29:20 -0800