import React from 'react';
import 'whatwg-fetch';
import './App.css';
import TimeForm from './TimeForm';
class App extends React.Component { constructor(props) {
super(props);
this.fetchCurrentTime = this.fetchCurrentTime.bind(this); this.handleFormSubmit = this.handleFormSubmit.bind(this); this.handleChange = this.handleChange.bind(this);
this.state = {
currentTime: null, msg: 'now' }
}
// methods we'll fill in shortly fetchCurrentTime() {}
getApiUrl() {}
handleFormSubmit(evt) {} handleChange(newState) {} render() {
const {currentTime, tz} = this.state; const apiUrl = this.getApiUrl(); return (
<div>
{!currentTime &&
<button onClick={this.fetchCurrentTime}> Get the current time
</button>}
{currentTime && <div>The current time is: {currentTime} </div>}
<TimeForm
onFormSubmit={this.handleFormSubmit} onFormChange={this.handleChange} tz={tz}
msg={'now'} />
<p>We'll be making a request from: <code>{apiUrl}</code></p> </div>
) } }
export default App;
The p e ious component is a basic stateful React component as e' e
c eated. Since e'll ant to sho a fo m, e' e included the intended usage of the TimeForm let's c eate ne t.
Let's c eate this component in ou eact app using create-react-app. Add
the file src/TimeForm.js into ou p oject:
touch src/TimeForm.js
No let's add content. We'll ant ou TimeForm to take the ole of allo ing
the use to s itch bet een timezones in thei b o se . We can handle this b c eating a stateful component e'll call the TimeForm. Ou TimeForm
import React from 'react'
const timezones = ['PST', 'MST', 'MDT', 'EST', 'UTC']
export class TimeForm extends React.Component { constructor(props) {
super(props);
this.fetchCurrentTime = this.fetchCurrentTime.bind(this); this.handleFormSubmit = this.handleFormSubmit.bind(this); this.handleChange = this.handleChange.bind(this);
const {tz, msg} = this.props; this.state = {tz, msg};
}
_handleChange(evt) {
typeof this.props.onFormChange === 'function' && this.props.onFormChange(this.state);
}
_changeTimezone(evt) {
const tz = evt.target.value;
this.setState({tz}, this._handleChange); }
_changeMsg(evt) { const msg =
encodeURIComponent(evt.target.value).replace(/%20/, '+'); this.setState({msg}, this._handleChange);
}
_handleFormSubmit(evt) { evt.preventDefault();
typeof this.props.onFormSubmit === 'function' && this.props.onFormSubmit(this.state);
}
render() {
const {tz} = this.state; return (
<select
onChange={this._changeTimezone} defaultValue={tz}>
{timezones.map(t => {
return (<option key={t} value={t}>{t}</option>) })}
</select> <input
type="text"
placeholder="A chronic string message (such as 7 hours from now)"
onChange={this._changeMsg} />
<input
type="submit"
value="Update request" />
</form> )
} }
export default TimeForm;
With these Components c eated, let's load up ou app in the b o se afte unning it ith npm start and e'll see ou fo m albeit not inc edibl
beautiful et . Of cou se, at this point, e on't ha e a unning component as e ha en't implemented ou data fetching. Let's get to that no .
As e said este da , e'll use the fetch() API ith p omise suppo t. When
e call the fetch() method, it ill etu n us a p omise, he e e can handle
the e uest ho e e e ant. We' e going to make a e uest to ou no - based API se e so sta t-up might be slo if it hasn't been un in a hile . We' e going to be building up the URL e'll e uest as it ep esents the time
ue e'll e uest on the se e .
I' e al ead defined the method getApiUrl() in the App component, so let's
fill that function in.
The ch onic api se e accepts a fe a iables that e'll customize in the fo m. It ill take the timezone to along ith a ch onic message. We'll sta t simpl and ask the ch onic lib a fo the pst timezone and the cu ent time
now :
class App extends React.Component { constructor(props) {
super(props); this.state = {
currentTime: null, msg: 'now', tz: 'PST' }
} // ...
getApiUrl() {
const {tz, msg} = this.state;
const host = 'https://andthetimeis.com'; return host + '/' + tz + '/' + msg + '.json'; }
// ...
export default App;
No , hen e call getApiUrl(), the URL of the ne t e uest ill be etu ned
fo us. No , finall , let's implement ou fetch() function. The fetch()
function accepts a fe a guments that can help us customize ou e uests. The most basic GET e uest can just take a single URL endpoint. The etu n
Let's update ou fetchCurrentTime() method to fetch the cu ent time f om
the emote se e . We'll use the .json() method on the esponse object to
tu n the bod of the esponse f om a JSON object into Ja aSc ipt object and then update ou component b setting the esponse alue of the dateString
as the currentTime in the component state:
class App extends React.Component { // ...
fetchCurrentTime() { fetch(this.getApiUrl()) .then(resp => resp.json()) .then(resp => {
const currentTime = resp.dateString; this.setState({currentTime})
}) } // ... }
The final piece of ou p oject toda is getting the data back f om the fo m to update the pa ent component. That is, hen the use updates the alues f om the TimeForm component, e'll ant to be able to access the data in the
App component. The TimeForm component al ead handles this p ocess fo
us, so e just need to implement ou fo m functions.
When a piece of state changes on the fo m component, it ill call a p op called onFormChange. B defining this method in ou App component, e can
get access to the latest e sion of the fo m.
In fact, e'll just call setState() to keep t ack of the options the fo m allo s
class App extends React.Component { // ...
handleChange(newState) { this.setState(newState); }
// ... }
Finall , hen the use submits the fo m clicks on the button or p esses ente in the input field , e'll ant to make anothe e uest fo the time. This means e can define ou handleFormSubmit p op to just call the
fetchCurrentTime() method:
class App extends React.Component { // ... handleFormSubmit(evt) { this.fetchCurrentTime(); } // ... }
T pla ing a ound ith the demo and passing in diffe ent ch onic options. It's actuall uite fun.
In an case, toda e o ked on uite a bit to get emote data into ou app. Ho e e , at this point, e onl ha e a single page in ou single page app. What if e ant to sho a diffe ent page in ou app? Tomo o , e' e going to sta t adding multiple pages in ou app so e can featu e diffe ent ie s.
Edit this page on Github (https://github.com/fullstackreact/30-days-of-react/blob/day-17/post.md)