-
-
Notifications
You must be signed in to change notification settings - Fork 26.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add docs for using Promises and making AJAX requests #531
Changes from 1 commit
9e460ac
358992f
012ca18
7af6adf
c068273
a94a24c
12aca13
8ec8ef0
d998dde
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -487,55 +487,91 @@ __About Promises:__ This project also includes a [Promise polyfill](https://gith | |
|
||
You can make a GET request like this: | ||
```javascript | ||
class MyComponent extends Component { | ||
import React, { Component, PropTypes } from 'react'; | ||
|
||
const { string } = PropTypes; | ||
|
||
class RepoList extends Component { | ||
static propTypes = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's remove propTypes. Not essential to this example and introduces class properties which we don't want for now. |
||
user: string.isRequired, | ||
} | ||
|
||
constructor(props) { | ||
super(props); | ||
this.state = {}; | ||
super(props) | ||
this.state = { repos: [] }; | ||
} | ||
|
||
componentDidMount() { | ||
this.fetchGists(); | ||
this.fetchRepos(this.props.user); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the person copies and pastes this component into App.js, user prop will be undefined. Can you make it so this is actually copy and pasteable with no modifications? I would suggest that, rather than display repos by user, let's display stargazers of facebook/react repo. Then we can hardcode it. |
||
} | ||
|
||
fetchGists() { | ||
fetch('https://api.github.com/users/octocat/gists') | ||
fetchRepos(user) { | ||
fetch(`https://api.github.com/users/${user}/repos`) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another subtle issue here is that Let's set a boolean instance field called |
||
.then((response) => response.json()) | ||
.then((gists) => this.setState({ gists })) | ||
.then((repos) => this.setState({ repos })) | ||
.catch((error) => console.log('Error', error)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a subtle problem here. If setState() throws (for example due to an error in render()), we will get into the catch handler. It is then easy to miss or ignore that error, and now React is in an inconsistent state. Instead, let's put catch() before the second then(). This way we only catch network errors. We want errors in setState() to stay unhandled. Let's make catch() return an empty array. Then we can safely use its result in setState() whether it succeeded or failed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also note that So to handle HTTP errors, you'll also have to check There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, @insin mentioned this later in a comment too. We should handle both |
||
} | ||
|
||
render() { | ||
return <UserGists gists={this.state.gists} />; | ||
return ( | ||
<ul> | ||
{this.state.repos.map((repo) => ( | ||
<li key={repo.full_name}> | ||
<a href={repo.html_url}>{repo.full_name}</a> | ||
</li> | ||
))} | ||
</ul> | ||
); | ||
} | ||
} | ||
|
||
export default RepoList; | ||
``` | ||
|
||
You can also use the `async/await` syntax to fetch data. [Here](https://zeit.co/blog/async-and-await) is an introduction to it. | ||
```javascript | ||
class MyComponent extends Component { | ||
import React, { Component, PropTypes } from 'react'; | ||
|
||
const { string } = PropTypes; | ||
|
||
class RepoList extends Component { | ||
static propTypes = { | ||
user: string.isRequired, | ||
} | ||
|
||
constructor(props) { | ||
super(props); | ||
this.state = {}; | ||
super(props) | ||
this.state = { repos: [] }; | ||
} | ||
|
||
componentDidMount() { | ||
this.fetchGists(); | ||
this.fetchRepos(this.props.user); | ||
} | ||
|
||
async fetchGists() { | ||
async fetchRepos(user) { | ||
try { | ||
const response = await fetch('https://api.github.com/users/octocat/gists'); | ||
const gists = await response.json(); | ||
this.setState({ gists }); | ||
const response = await fetch(`https://api.github.com/users/${user}/repos`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would need to be adjusted to match the behavior I mentioned above. |
||
const repos = await response.json(); | ||
this.setState({ repos }); | ||
} catch(error) { | ||
console.log('Error', error); | ||
} | ||
} | ||
|
||
render() { | ||
return <UserGists gists={this.state.gists} />; | ||
return ( | ||
<ul> | ||
{this.state.repos.map((repo) => ( | ||
<li key={repo.full_name}> | ||
<a href={repo.html_url}>{repo.full_name}</a> | ||
</li> | ||
))} | ||
</ul> | ||
); | ||
} | ||
} | ||
|
||
export default RepoList; | ||
``` | ||
|
||
## Integrating with a Node Backend | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's keep it called App so it's obvious this code can be copy and pasted into App.js.