[笔记] React 如何使用 Redux-Observable 及 Google Map Api:副线打怪一下(3)

口罩即时查

先附上作品网址及成果展示:口罩即时查
http://img2.58codes.com/2024/20123842MX2os0BFo8.png
http://img2.58codes.com/2024/20123842wGKhHPQjjn.png

功能(电脑、平板、手机皆可观看)

电脑版 ᴘᴄ
平板 ᴛ
手机版 ᴍ

定位 - 在地图上显示目前位置 ᴘᴄ药局显示 - 在地图上显示药局药局列表 ᴛ、ᴍ (点选药局可以快速前往目前位置) ᴘᴄ滑鼠滑过marker时显示口罩剩余数量 ᴘᴄ点击marker时显示药局营业时间及备注 ᴘᴄ搜寻 - 亦可于搜寻框中搜寻欲查询的药局资讯(输入药局名称、区域及地址皆可)ᴘᴄ、ᴛ、ᴍ回到现在位置钮 - 点选地图右侧的蓝色按钮可以回到现在位置 ᴘᴄ拨打电话 - 点选按钮可以快速联繫药局来询问详细资讯 ᴘᴄ、ᴛ、ᴍ

程式码纪录(Redux-Observable)

上篇文章已经可以成功抓取药局资讯,这边会着重于纪录将药局资讯显示到画面上的过程,那就继续看下去吧!
发送请求的action

/* actions/index.js *///发送 口罩资讯requestexport const fetchMaskInformation = (callback) => {    return {        type: 'FETCH_MASK_INFORMATION',        callback    };}//接收口罩资讯export const recieveMaskInformation = (res, updateTime) => {    return {        type: 'RECIEVE_MASK_INFORMATION',        res: res,        updateTime: updateTime,    };}

epic函数

/* epics/index.js */const maskGetList = (action$) =>     action$.ofType('FETCH_MASK_INFORMATION').pipe(    mergeMap(({callback}) => {         return merge(            //发送request时设定isLoading为true来告知使用者正在抓取资料            of(actions.maskInformationIsLoading(true)),              ajax.getJSON(`网址`).pipe(                mergeMap(response => {                    // console.log(response.features);                    // 传入callback function                    if(callback) callback(response.features);                    // 更新时间                    const updateTime = response.features[0].properties.updated;                     return of(                        // fetch完之后再次发送action将资料存到reducer                        actions.recieveMaskInformation(response.features, updateTime),                        // 收到response后设定isLoading为false告知使用者抓取资料完成                        actions.maskInformationIsLoading(false),                    );                })            )        )    }));

将fetch资料存到reducer调用

/* reducers/index.js */const model = {    maskInformationLists: [],    updateTime: '',};const Reducer = (state = model, action) => {    switch (action.type) {        case 'RECIEVE_MASK_INFORMATION':            return {                ...state,                maskInformationLists: action.res,                updateTime: action.updateTime,            }                    default:            return state;    }};export default Reducer;

接下来的部分就是Redux的使用啦http://img2.58codes.com/2024/emoticon01.gif,就不再另外纪录Redux的部分。

程式码纪录(Google Map Api)

Google Map 使用的是itsmichaeldiego作者开发的google-map-react套件

安装

npm install --save google-map-react

or

yarn add google-map-react

程式码

...class map extends Component {    constructor() {        super();        this.state = {            center: center,            zoom: 16,            features: [],        };    }        ...    // 取得目前位置    getLocation = () => {        if (navigator.geolocation) {            navigator.geolocation.getCurrentPosition(this.updateLocation);        }    }    // 取得目前位置后插上marker并且将现在位置设定为中心点    updateLocation = (position) => {        this.setState({            center: {                lat: position.coords.latitude,                lng: position.coords.longitude,            }        }, () => {            // console.log(this.map);            // 定位完成后,删掉起始位置的marker            this.marker.setMap(null);            // 新增现在位置的marker            this.marker = new google.maps.Marker({                position: new google.maps.LatLng(this.state.center.lat, this.state.center.lng),                map: this.map,                // 自订icon图示                icon: location            });            this.map.setCenter(this.state.center);            this.map.setZoom(16);          });    }   ...    handleApiLoaded = (map) => {        this.map = map;         // 给定初始位置,如果使用者不允许抓取现在位置时则使用初始位置        this.marker = new google.maps.Marker({            position: new google.maps.LatLng(this.state.center.lat, this.state.center.lng),            map: this.map,            icon: location,        });        // 在Google Map上新增custom button        // constructor passing in this DIV.        var controlDiv = document.createElement('div');        // Set CSS for the control border.        var controlUI = document.createElement('div');        controlUI.style.backgroundColor = '#fff';        controlUI.style.border = '2px solid #fff';        controlUI.style.borderRadius = '3px';        controlUI.style.boxShadow = '0 2px 6px rgba(0,0,0,.3)';        controlUI.style.cursor = 'pointer';        controlUI.style.marginRight = '10px';        controlUI.style.textAlign = 'center';        controlUI.title = 'Click to recenter the map';        controlDiv.appendChild(controlUI);        // Set CSS for the control interior.        var controlText = document.createElement('div');        controlText.style.color = 'rgb(25,25,25)';        controlText.style.fontFamily = 'Roboto,Arial,sans-serif';        controlText.style.fontSize = '16px';        controlText.style.lineHeight = '38px';        controlText.style.paddingLeft = '5px';        controlText.style.paddingRight = '5px';        controlText.innerHTML = `<img src=${centerGPS} alt=""></img>`;        controlUI.appendChild(controlText);        // Setup the click event listeners: simply set the map to Chicago.        controlUI.addEventListener('click', this.getLocation);        this.map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(controlDiv);        // ApiLoaded完之后才fetch        this.props.fetchMaskInformation(this.createMarker);        this.getLocation();    };    createMarker = () => {        // 在此function插marker、建立infowindows动作、marker cluster                ...    }    render() {        const { classes } = this.props;        return (            <div className={classes.container}>                <GoogleMapReact                    bootstrapURLKeys={{ key: /* YOUR KEY HERE */ }}                    defaultCenter={center}                    defaultZoom={this.state.zoom}                    yesIWantToUseGoogleMapApiInternals                    onGoogleApiLoaded={({ map, maps }) => this.handleApiLoaded(map, maps)}                >                </GoogleMapReact>            </div>        );    }}

参考来源:
google-map-react
Maps JavaScript API

以上是这次口罩练习的纪录,之后如果还有加上typescript的话会再补充上来。

心得

透过这次的口罩练习确实的把Redux及Observable好好的实作一次,从中更了解了从发送request到接收到response再到呈现到画面上的整个流程之外,也在途中发生了一个小插曲,让我体会到Observable的方便之处,也觉得自己的战斗力提升了不少XD
那就来分享个小插曲,前几篇文有提到Observable的优点以及分享了Netflix发表的演讲影片来叙述为什么要使用Observable,当时只是知道说原来有这样的优点,但还是抱持着真的有这么好用吗的想法,这次在处理药局资讯的response时我就因为同时发送fetch以及Google map api产生了不同步行为,要是fetch先完成那没问题,地图会正常显示并且插上marker,但若是因为网路问题或是其他因素导致fetch较慢完成,就会造成地图先loaded完成,却没有插上各个药局的marker,所以使用Observable就能轻鬆地解决这个问题,这就是Observable的强大啊!!

问题与讨论

我也是前端的小菜鸟,所以要是有什么写得不好的地方,大师路过还请多给我一些指点,也请各位大师鞭小力点XD
如果你/妳已经是在前端上有一两年经验的,因本系列文章偏向前端入门,可能本系列文章不太适合你/妳,但也欢迎你/妳给予一些建议。


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章