{"id":1769,"date":"2019-03-04T18:05:58","date_gmt":"2019-03-04T18:05:58","guid":{"rendered":"https:\/\/www.codeastar.com\/?p=1769"},"modified":"2019-06-28T07:37:59","modified_gmt":"2019-06-28T07:37:59","slug":"react-frontend-weather-forecast-2","status":"publish","type":"post","link":"https:\/\/www.codeastar.com\/react-frontend-weather-forecast-2\/","title":{"rendered":"React Frontend and Flask Backend for Weather Forecast \u2013 Part 2"},"content":{"rendered":"\n
From our last post, “Flask Backend and React Frontend for Weather Forecast \u2013 Part 1<\/a>“, we built our magic user, RESTful API as the backend module with Flask. This time, we are going to build our sword swinger, who always deals with challenges at the front line. Before we go further, let’s have a little rewind. Do you remember why we separate web app into backend and frontend modules? Yes, I know you can answer it (don’t you? :]] ). Because of utilizing both modules to their max capability. From our 2019 Top Programming Languages<\/a> post, we mentioned that frontend languages are much stronger nowadays and hot in job market. Although we have focused on Python backend mostly in this blog, it is a valuable experience to taste the frontend languages. So, let’s enter our new page of frontend languages, and code our React Frontend for the EZ Weather Forecast (EZW) project.<\/p>\n\n\n\n\n\n\n\n Yes, why React? Since there are several frontend languages, like Angular and Vue.js. Our reasons of choosing React<\/a> are: ease of use, popularity and the size of community. Actually, those are also the reasons we pick Python as our major language as well. It will be easier if we try something new which is similar to something we are familiar with.<\/p>\n\n\n\n Oh wait, you don’t have any React experience? No problem, then we go for it step-by-step. First things first, even though we always use the term “frontend languages”, they are all JavaScript framework or library. In order to write our frontend (JavaScript) module, we need a JavaScript runtime — Node.js<\/a>. Go to download the latest stable version and run following command to start our first ever React frontend: <\/p>\n\n\n\n Thus we have started our first ever React frontend module on http:\/\/localhost:3000. We have prepared our development environment, so it is time to update the generic boilerplate to our actual EZW frontend.<\/p>\n\n\n\n Before we start our coding, let’s define our expected outcome. On our previous EZW single module setup<\/a>, we have following user interface: <\/p>\n\n\n\n So our requirements are: a pair of date pickers , a location input box and a submit button for our frontend. <\/p>\n\n\n\n Okay, let’s go back to our “ezw_react<\/em>” folder and start our coding. First, remove all files within “ezw_react\/src<\/em>” folder. Yes, remove them all. Don’t panic, we just remove unwanted files and replace files that matter later. Then, we go to install required packages for “ezw_react<\/em>” using npm<\/em>. Npm<\/em> is a package manager tool, so you can think about it as Node.js version of Python’s pipenv<\/a><\/em>. We install following packages:<\/p>\n\n\n\n with the command, npm install <package_name> –save<\/em>. <\/p>\n\n\n\n After that, we create a index.js<\/em> file under “src” folder with following content: <\/p>\n\n\n\n Open http:\/\/localhost:3000<\/em> in the browser, you should see our date pickers created using React.<\/p>\n\n\n\n Ta-Da! We just made our first React app by ourselves! There are major code blocks in our source, index.js<\/em>: <\/p>\n\n\n\n We have all the basic setup for our date pickers. The next thing we need to do is adding logic to our Ezw React component. Do you remember the states and date methods we created in previous step? Now we are going to use them to get date information into the Ezw component. So we update the Ezw component with: <\/p>\n\n\n\n From our single module EZW Flask solution, we handled geolocation in backend. And we mentioned in past, the modern day frontend languages are more powerful, they can handle some of the backend tasks as well. So why don't we take the advantage of frontend module and provide user a better user experience? Thus we have the React GeoSuggest package.<\/p>\n\n\n\n The idea of GeoSuggest is easy, we let user enter a part of a location and we provide a list of suggestion from Google map. Since it is a Google service, we have to use Google web service API key. Let's move to Google Developer Console<\/a> for key generation. After that, we enable Google Maps Geocoding API<\/a>, Google Places API Web Service<\/a> and Google Maps Javascript API<\/a> to make the React GeoSuggest package work.<\/p>\n\n\n\n Now we have the API key and the enabled services. Other than we hard code the key into our source, there is a better way to handle variables in React --- by using a .env<\/strong> file. The .env<\/strong> file should be located under the root folder at: <\/p>\n\n\n\n We put REACT_APP_GOOGLE_API_KEY=<your Google API key><\/em> in the .env<\/strong> file. And then we put <script src=\"https:\/\/maps.googleapis.com\/maps\/api\/js?key=%REACT_APP_GOOGLE_API_KEY%&libraries=places\"><\/script><\/em> into the <head><\/head><\/em> section of \/ezw_react\/public\/index.html<\/strong>.<\/p>\n\n\n\n Okay, we have finished the Google API setting, now it is the time we bring the GeoSuggest to live. First, we add new states and methods in constructor:<\/p>\n\n\n\n Second, we define new location methods, which obtain location information from Google: <\/p>\n\n\n\n Finally, we put the GeoSuggest object in Render() method: <\/p>\n\n\n\n Please note that we have added a default location \"Mountain View\" and 2 fixture locations, \"Mountain View Station\" and \"Mountain Public Library\". Those settings are optional, as we just want to try more of the GeoSuggest package. We also apply CSS setting to make the EZW app look fancy, and you can get the complete source at the end of this topic. Then we have: <\/p>\n\n\n\n The first two suggestions in red rectangle are the ones we entered in above code. While others are place suggestions returned from Google Places API! Let's review our current process. A pair of date packers? Check! Geo suggestion? Check! Now we only need a submit button and a layout of our weather report.<\/p>\n\n\n\n We are almost there. In order to get weather reports, we need to send our request with JSON to our EZW Flask backend module. Like the way we setup Google API key, we can set the EZW backend url at .env<\/strong> file. Assuming the EZW Flask backend is set at http:\/\/127.0.0.1:5000\/ezw_api<\/em>, so we put following line in the .env <\/strong>file:<\/p>\n\n\n\n Update index.js<\/em> by adding following functions:<\/p>\n\n\n\n Those functions define our weather report layout, using the JSON response from EZW backend. Please note that we use a React package, react-icons-weather<\/em>, to display weather icons from Dark Sky API. <\/p>\n\n\n\n Now we add the part that sends out a JSON request to our EZW backend:<\/p>\n\n\n\n You may notice that we are using 2 JavaScript packages on above code: axios <\/em>and moment<\/em>. Axios <\/em>is our HTTP client for handling HTTP request\/response. The major benefits of using axios<\/em> are: 1) it is promise<\/a> based and 2) it is JSON ready. And for the moment<\/em> package, it is a popular JavaScript package for handling and formatting date object.<\/p>\n\n\n\n The getDateResult <\/em>function is straight forward, it collects date and location information from our UI, then send a JSON request and receive a JSON response to\/from our EZW Flask backend. Our EZW backend url is defined by the environment variable, process.env.REACT_APP_EZW_API<\/em>. And yes, it is the REACT_APP_EZW_API<\/em> variable we set on the .env<\/strong> file earlier.<\/p>\n\n\n\n We have all the functions ready, then it is the time we render the submit button and weather report:<\/p>\n\n\n\nWhy React Frontend? <\/h3>\n\n\n\n
$npx create-react-app ezw_react\n$cd ezw_react\n$npm start<\/code><\/pre>\n\n\n\n
EZW Frontend with React<\/h3>\n\n\n\n
<\/figure><\/div>\n\n\n\n
import React from 'react';\nimport ReactDOM from 'react-dom';\nimport DatePicker from \"react-datepicker\"; \nimport \"react-datepicker\/dist\/react-datepicker.css\";\n\nclass Ezw extends React.Component {\n\n constructor(props) {\n super(props);\n this.state = \n {\n startDate: new Date(),\n endDate: new Date(), \n }; \n this.handleChangeStart = this.handleChangeStart.bind(this);\n this.handleChangeEnd = this.handleChangeEnd.bind(this);\n }\n\n handleChangeStart(date) \n {\n }\/\/handleChangeStart\n\n handleChangeEnd(date) \n {\n }\/\/handleChangeEnd\n \n render() \n {\n return ( \n
EZ Weather Forecast React Frontend<\/h1>\n
<\/figure><\/div>\n\n\n\n
handleChangeStart(date) \n {\n if (date > this.state.endDate)\n {\n this.setState({\n endDate: date\n });\n }\n\n this.setState({\n startDate: date\n });\n\n }\/\/handleChangeStart\n\n handleChangeEnd(date) \n {\n if (date < this.state.startDate)\n {\n this.setState({\n startDate: date\n });\n }\n\n this.setState({\n endDate: date\n });\n }\/\/handleChangeEnd\n<\/pre>\n\n\n\n
Handle Geolocation with Google API <\/h3>\n\n\n\n
\/ezw_react\n \/src \n index.js\n index.css\n \/public\n index.html\n package.json\n .env <\/code><\/pre>\n\n\n\n
React GeoSuggest in Action<\/h3>\n\n\n\n
import Geosuggest from 'react-geosuggest';\n\n constructor(props) {\n super(props);\n this.state = \n {\n ....\n latitude: null,\n longitude: null,\n readyToSubmit: false, \n location: null,\n status: \"Enter date and location...\"\n };\n ....\n this.handleLocation = this.handleLocation.bind(this);\n this.resetLocation = this.resetLocation.bind(this);\n }\n<\/pre>\n\n\n\n
handleLocation(loc)\n {\n if (typeof loc !== 'undefined')\n { \n this.setState({\n latitude: loc.location.lat,\n longitude: loc.location.lng,\n location: loc.label,\n readyToSubmit: true,\n status: \"Ready to Send\"\n });\n }\n }\/\/handleLocation\n\n resetLocation() \n {\n this.setState({\n latitude: null,\n longitude: null,\n readyToSubmit: false,\n status: \"Enter date and location...\"\n });\n }\/\/resetLocation\n<\/pre>\n\n\n\n
render() \n {\n var fixtures = [\n {label: 'Mountain View Station, Mountain View, CA, USA', location: {lat: 37.3945565, lng: -122.0782263}}, \n {label: 'Mountain View Public Library, Franklin St, Mountain View, CA, USA', location: {lat: 37.3968885, lng: -122.0929291}}, \n ];\n\n return ( \n
<\/figure><\/div>\n\n\n\n
Get Weather Report from Backend<\/h3>\n\n\n\n
REACT_APP_EZW_API=http:\/\/127.0.0.1:5000\/ezw_api<\/code><\/pre>\n\n\n\n
import WeatherIcon from 'react-icons-weather';\n\nfunction cardLayout(props, i)\n{\n return (\n
import axios from 'axios';\nimport moment from 'moment';\n\nclass Ezw extends React.Component {\n constructor(props) {\n ....\n this.getDateResult = this.getDateResult.bind(this);\n }\n\n getDateResult()\n {\n this.setState({\n status: \"Processing...\",\n });\n \/\/send to server \n let json_req = {\"latitude\": this.state.latitude, \"longitude\": this.state.longitude, \n \"start_date\": moment(this.state.startDate).format('YYYY-MM-DD'), \"end_date\":moment(this.state.endDate).format('YYYY-MM-DD')};\n axios.post(process.env.REACT_APP_EZW_API,json_req)\n .then(res => {\n this.setState({\n status: Weathercard(res.data)\n });\n }) \/\/axios \n }\/\/getDateResult\n<\/pre>\n\n\n\n
\n render() \n {\n ....\n let weather_report;\n weather_report = this.state.status;\n\n return (\n