See this project hosted on Heroku! https://tennis-weather-app.herokuapp.com/
- Built using ReactJS and the Open Weather Map API
- log in to Heroku on Command Line
$ heroku login
- clone the repository
$ heroku git:clone -a tennis-weather-app
- since the app is in the subdirectory, use this command to push to heroku remote
$ git commit -m "committing..."
$ git subtree push tennis-weather-app heroku master
- there was an H10 error:
heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/"
- to resolve this, need to install serve
npm i serve
and modify thepackage.json
so that onnpm start
, it runsserve -s build
instead ofreact-scripts start
due to port issues, and change the scripts:
"dev": "react-scripts start",
"start": "serve -s build",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"heroku-postbuild": "npm run build"
}
- also don't delete favicon.ico :(
- using open API from openweathermap.org
- to use this API, create a const variable in the App.js file with a key (API key) and base (url of the API location)
- if you want to use this to get the weather, use a fetch function
fetch(`${api.base}weather?q=${query}&units=metric&APPiD=${api.key}`)
.then(res =>res.json())
.then(result => setWeather(result));
- sends an HTTP request to this base website and uses the API key to get put this endpoint
- get json from the response and set the weather to this result
onChange={e => setQuery(e.target.value)}
- include this onChange function in the search bar in order to call event when it is happening
- need to check if the weather.main is defined and has been called
- use the ternary operator and need to enclose all in a div tag
{(typeof weather.main != "undefined") ? () : (' ')}
- can also update the background picture based on the weather with this class in the div returned
<div className={
(typeof weather.main != "undefined")
? ((weather.main.temp > 16)
? 'App warm'
: 'App cold')
: 'App'}>
- for time, can add a '0' to the beginning of the getTime() return value, then use .slice(-2) to get last two digits
- also going to be using a backend server
- npm install the express, mysql, nodemon, and body-parser
- we'll be running this server on port 3001 instead of 3000
- now instead of using npm start to run the application, we use
node index.js
- here, we're also using the app.get to reach the home location, REST API
- can configure nodemon so that it knows we're running the application and continuously update
- in the scripts of the
package.json
set it so when you do start, it automatically runs node index.js - also add
"devStart": "nodemon index.js"
to run the server through nodemon - now, command:
npm run devStart
- a lot of people actually use this so they don't need to re run the server when developing
- using MySQL to store the previous cities and their temperatures
- access the MySQL database in the index.js of the server using this
const mysql = require('mysql');
- then we need to create an instance from mysql with the same database name as the one in our local instance
const db = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'tennis-weather-database'
})
- host is the address of the site; right now it's just localhost
- root and password are defaults
- to call a command and insert into the database, use the query function
- query function takes in a string to pass to the table, so need to use the key words
- instead of (req, res), can use (err, result) to see if there are errors and return whatever trying to query
- React uses a virtual DOM, which stands for document object model
- basically, it creates the hierarchy virtually in the memory (RAM) and if it finds a difference between the virtual and the screen (UI) DOM, it updates automatically
- so page does not need to be refreshed, it updates automatically
- JSX is Javascript XML, similar to HTML
- JSX allows you to return a block of XML to create HTML content
- must have enclosing tags when returning (like returning a div instead of an 'a' and an 'h1' tag)
- JavaScript expressions allows to insert JS into the JSX code
{this.props.caption}
- index.js file contains the import of React, as well as rendering for the ReactDOM
- when rendering, the App tag calls the App.js file
- when you save, the virtual DOM automatically updates the website in localhost
- functional components are static and don't really change, no states
- React is just a framework for Javascript, so need to import it in every file
- once you define a component and it returns something (like an image in a div) need to export it
export default BannerImage;
- need to import the image and include the location of it in the files into App.js
- to include the component which renders the code, use the self closing tag of the component
- in the JSX, use
<BannerImage />
- when importing, if it is a JS extension, don't need to specify; but for css and others, you do
- instead of adding class="" in the tag, for JSX need to use className=""
- class based components are dynamic and better for things that have to change
- props, short for properties, can be passed into the components
<PhotoEntry src="berlin.jpg" location="Location" /> // src and location parameters
- to access these parameters in the component React js file, use this.props.{parameter} where props is for specific property
this.props.caption or this.props.location
- when including Javascript, or a variable in the JSX, need to use {} around it
- when including and image as the src, need to include the specific path, like ".../images/" + this.props.src
- otherwise, can just use the this.props expression
- can create a "wrapper-like" component that just hard codes some instances of another component
- instead of creating hardcoding the parameters, can use JSON to create them dynamically
- can import the json file by doing
import NAME_OF_OBJECT from './data/JSON_FILE'
- when commenting, JSX has to think it is JavaScript so need to enclose the comment in braces {/**/}
- example of using the JSON file:
{
entries.itemlist.map((photo) => {
return <PhotoEntry key={photo.src} src={photo.src} location={photo.location} caption={caption} />
)
}
- photo is the current element in the entries list, getting the properties from it
- adding in a 'key' property helps React update the DOM quickly
debugger;
triggers a breakpoint in the code and pauses execution in the code
- class-based components have states and lifestyles
- props are something from the outside that are passed into the React component
- on the other hand, state is internal and component keeps it for itself, can only be changed by the component itself
- state determines whether component is re-rendered or not
- set and get a state:
this.setState({x: y}) this.state.attribute
- call the constructor with
constructor(props) {}
and super(props) to initialize with parent constructor - initialize the state by doing
this.state = {userID: "", userName: ""};
where it contains key/value pairs
- controlled components help with maintaining the state
- when someone types something in a box, it triggers the onChange event and it saves the new value on each keystroke into the state
- so now you read what is in the state, not in the text box
- everytime there is a keystroke, onChange calls a function that takes in an event
- to get the value of the event that was passed in, (the userIdFieldValue that was typed in the text box) use
event.target.value
- use
let
keyword to declare a variable
- render prop is when you use a component to create a prop that can be used where the component was called
<UserManager showMessageArea={ userInfo => (<MessageArea userInfo={userInfo} />)} />
- this returns a prop called showMessageArea that takes in an argument...can use it with
this.props.showMessageArea(this.state)
- context means when you create a context component, any component below in the hierarchy will have access to the data in the context
- in context, doesn't need to be passed as a prop all the way down, can just be accessed
- each context has a provider (provides the values) and consumers (use the values); need to import the context
- in the render, enclose the tags in a provider tag and return it; the value is whatever you want the components inside the tags to be able to access it
<ContentAreaContext.Provider value={{userIs: this.state.userId}}> </ContentAreaContext.Provider>
- when you want to consume the values of the context, go into the file, import context, and create a
static contextType = ContentAreaContext;
- use the context by calling this.context.VALUE_NAME_HERE (different from the contextType)
- when class components get created and destroyed, they go through stages and cycles of their lives
- these are all methods that you can call in the component or in the App.js
- Mounting methods (component created)
- constructor- actual creation of component
- render- displays component to the screen
- componentDidMount- stage when all the component and its children have already been rendered
- Update methods (component being updated)
- shouldComponentUpdate- passes you old and new state, and can decide to re-render
- render
- componentDidUpdate- after the state changes
- Unmounting methods (component destroyed)
- componentWillUnmount- can do some cleanup before the component is destroyed
- used to transfer data between different branches of the app
- in the component you want to get data from, you have an event with an observer list that contains the components that you want to notify when the event happens
- "subscribed" components in this list will get notified upon event
- can check if the state has been changed using the componentDidUpdate() function, and call ALL event listeners in the subscribe list