From 9e460acc4ef50c875df6ad988292108988b578bd Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Wed, 31 Aug 2016 17:26:02 -0700 Subject: [PATCH 1/7] Add docs for using Promises and making AJAX requests --- template/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/template/README.md b/template/README.md index 31c2802d041..50b37bd9451 100644 --- a/template/README.md +++ b/template/README.md @@ -23,6 +23,8 @@ You can find the most recent version of this guide [here](https://github.com/fac - [Adding Custom Environment Variables](#adding-custom-environment-variables) - [Integrating with a Node Backend](#integrating-with-a-node-backend) - [Proxying API Requests in Development](#proxying-api-requests-in-development) +- [Using Promises](#using-promises) +- [AJAX Requests](#ajax-requests) - [Adding `` Tags](#adding-meta-tags) - [Deployment](#deployment) - [Now](#now) @@ -504,6 +506,32 @@ If the `proxy` option is **not** flexible enough for you, alternatively you can: * Enable CORS on your server ([here’s how to do it for Express](http://enable-cors.org/server_expressjs.html)). * Use [environment variables](#adding-custom-environment-variables) to inject the right server host and port into your app. +## Using Promises + +This project includes a [Promise polyfill](https://github.com/then/promise) which provides a full implementation of Promises/A+. + +A Promise represents the eventual result of an asynchronous operation, you can find more information about Promises [here](https://www.promisejs.org/) and [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). + +## AJAX Requests + +This project includes a [fetch polyfill](https://github.com/github/fetch), which makes it easier to make web requests. + +The `fetch` function allows to easily makes AJAX requests. It takes in a url or a Request as an input and returns a Promise that resolves to a Response object. You can find more information about `fetch` [here](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). + +While you can still use `new XMLHttpRequest`, we encourage you to use `fetch`. + +You can make a GET request like this: +```javascript + fetch('/todos.json') // Make the request + .then(function(response) { + return response.json(); // Parse the JSON response (optional) + }).then(function(todos) { + console.log('Todos', todos); // Handle success + }).catch(function(error) { + console.log('Error', error); // Handle error + }); +``` + ## Adding `` Tags You can edit the generated `index.html` and add any tags you’d like to it. However, since Create React App doesn’t support server rendering, you might be wondering how to make `` tags dynamic and reflect the current URL. From 358992fe3c0ae1ac20df36f90471ec9a2e8fe1c3 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Sat, 3 Sep 2016 09:19:00 -0700 Subject: [PATCH 2/7] Small polish to AJAX requests docs based on @gaearon comments --- template/README.md | 85 +++++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/template/README.md b/template/README.md index 50b37bd9451..c61417a8194 100644 --- a/template/README.md +++ b/template/README.md @@ -21,10 +21,9 @@ You can find the most recent version of this guide [here](https://github.com/fac - [Adding Bootstrap](#adding-bootstrap) - [Adding Flow](#adding-flow) - [Adding Custom Environment Variables](#adding-custom-environment-variables) +- [Fetching AJAX Requests](#fetching-ajax-requests) - [Integrating with a Node Backend](#integrating-with-a-node-backend) - [Proxying API Requests in Development](#proxying-api-requests-in-development) -- [Using Promises](#using-promises) -- [AJAX Requests](#ajax-requests) - [Adding `` Tags](#adding-meta-tags) - [Deployment](#deployment) - [Now](#now) @@ -465,6 +464,62 @@ if (process.env.NODE_ENV !== 'production') { } ``` +## Fetching AJAX Requests + +This project includes a [fetch polyfill](https://github.com/github/fetch), which makes it easier to make web requests. + +The `fetch` function allows to easily makes AJAX requests. It takes in a URL as an input and returns a `Promise` that resolves to a `Response` object. You can find more information about `fetch` [here](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). + + +__About Promises:__ This project also includes a [Promise polyfill](https://github.com/then/promise) which provides a full implementation of Promises/A+. A Promise represents the eventual result of an asynchronous operation, you can find more information about Promises [here](https://www.promisejs.org/) and [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). + +You can make a GET request like this: +```javascript +class MyComponent extends Component { + state = {} + + componentDidMount() { + this.fetchGists(); + } + + fetchGists() { + fetch('https://api.github.com/users/octocat/gists') + .then((response) => response.json()) + .then((gists) => this.setState({ gists })) + .catch((error) => console.log('Error', error)); + } + + render() { + return ; + } +} +``` + +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 { + state = {} + + componentDidMount() { + this.fetchGists(); + } + + async fetchGists() { + try { + const response = await fetch('https://api.github.com/users/octocat/gists'); + const gists = await response.json(); + this.setState({ gists }); + } catch(error) { + console.log('Error', error); + } + } + + render() { + return ; + } +} +``` + ## Integrating with a Node Backend Check out [this tutorial](https://www.fullstackreact.com/articles/using-create-react-app-with-a-server/) for instructions on integrating an app with a Node backend running on another port, and using `fetch()` to access it. You can find the companion GitHub repository [here](https://github.com/fullstackreact/food-lookup-demo). @@ -506,32 +561,6 @@ If the `proxy` option is **not** flexible enough for you, alternatively you can: * Enable CORS on your server ([here’s how to do it for Express](http://enable-cors.org/server_expressjs.html)). * Use [environment variables](#adding-custom-environment-variables) to inject the right server host and port into your app. -## Using Promises - -This project includes a [Promise polyfill](https://github.com/then/promise) which provides a full implementation of Promises/A+. - -A Promise represents the eventual result of an asynchronous operation, you can find more information about Promises [here](https://www.promisejs.org/) and [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). - -## AJAX Requests - -This project includes a [fetch polyfill](https://github.com/github/fetch), which makes it easier to make web requests. - -The `fetch` function allows to easily makes AJAX requests. It takes in a url or a Request as an input and returns a Promise that resolves to a Response object. You can find more information about `fetch` [here](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). - -While you can still use `new XMLHttpRequest`, we encourage you to use `fetch`. - -You can make a GET request like this: -```javascript - fetch('/todos.json') // Make the request - .then(function(response) { - return response.json(); // Parse the JSON response (optional) - }).then(function(todos) { - console.log('Todos', todos); // Handle success - }).catch(function(error) { - console.log('Error', error); // Handle error - }); -``` - ## Adding `` Tags You can edit the generated `index.html` and add any tags you’d like to it. However, since Create React App doesn’t support server rendering, you might be wondering how to make `` tags dynamic and reflect the current URL. From 7af6adf0bff0459990d4a4eefef3020685085926 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Sat, 3 Sep 2016 23:43:17 -0700 Subject: [PATCH 3/7] Use constructor instead of es7 class properties --- template/README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/template/README.md b/template/README.md index 7777e6b2fc8..dc9e3bd5279 100644 --- a/template/README.md +++ b/template/README.md @@ -480,7 +480,7 @@ Create React App will add decorator support when the specification advances to a This project includes a [fetch polyfill](https://github.com/github/fetch), which makes it easier to make web requests. -The `fetch` function allows to easily makes AJAX requests. It takes in a URL as an input and returns a `Promise` that resolves to a `Response` object. You can find more information about `fetch` [here](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). +The global `fetch` function allows to easily makes AJAX requests. It takes in a URL as an input and returns a `Promise` that resolves to a `Response` object. You can find more information about `fetch` [here](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). __About Promises:__ This project also includes a [Promise polyfill](https://github.com/then/promise) which provides a full implementation of Promises/A+. A Promise represents the eventual result of an asynchronous operation, you can find more information about Promises [here](https://www.promisejs.org/) and [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). @@ -488,7 +488,10 @@ __About Promises:__ This project also includes a [Promise polyfill](https://gith You can make a GET request like this: ```javascript class MyComponent extends Component { - state = {} + constructor(props) { + super(props); + this.state = {}; + } componentDidMount() { this.fetchGists(); @@ -510,7 +513,10 @@ class MyComponent extends Component { 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 { - state = {} + constructor(props) { + super(props); + this.state = {}; + } componentDidMount() { this.fetchGists(); From c068273b3a12a319c99691b49851ff46d86c24f0 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Sun, 4 Sep 2016 22:15:28 -0700 Subject: [PATCH 4/7] Modify the ajax request example to make it easier for people to copy/paste it --- template/README.md | 70 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/template/README.md b/template/README.md index dc9e3bd5279..d3ee8f40599 100644 --- a/template/README.md +++ b/template/README.md @@ -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 = { + user: string.isRequired, + } + constructor(props) { - super(props); - this.state = {}; + super(props) + this.state = { repos: [] }; } componentDidMount() { - this.fetchGists(); + this.fetchRepos(this.props.user); } - fetchGists() { - fetch('https://api.github.com/users/octocat/gists') + fetchRepos(user) { + fetch(`https://api.github.com/users/${user}/repos`) .then((response) => response.json()) - .then((gists) => this.setState({ gists })) + .then((repos) => this.setState({ repos })) .catch((error) => console.log('Error', error)); } render() { - return ; + return ( + + ); } } + +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`); + const repos = await response.json(); + this.setState({ repos }); } catch(error) { console.log('Error', error); } } render() { - return ; + return ( + + ); } } + +export default RepoList; ``` ## Integrating with a Node Backend From a94a24cc1d9a9677863a31b77dd60eec38f4e430 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Mon, 5 Sep 2016 12:15:09 -0700 Subject: [PATCH 5/7] Remove propTypes from AJAX example and rename component to App --- template/README.md | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/template/README.md b/template/README.md index d3ee8f40599..c4463e9b10c 100644 --- a/template/README.md +++ b/template/README.md @@ -487,15 +487,9 @@ __About Promises:__ This project also includes a [Promise polyfill](https://gith You can make a GET request like this: ```javascript -import React, { Component, PropTypes } from 'react'; - -const { string } = PropTypes; - -class RepoList extends Component { - static propTypes = { - user: string.isRequired, - } +import React, { Component } from 'react'; +class App extends Component { constructor(props) { super(props) this.state = { repos: [] }; @@ -525,20 +519,14 @@ class RepoList extends Component { } } -export default RepoList; +export default App; ``` 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 -import React, { Component, PropTypes } from 'react'; - -const { string } = PropTypes; - -class RepoList extends Component { - static propTypes = { - user: string.isRequired, - } +import React, { Component } from 'react'; +class App extends Component { constructor(props) { super(props) this.state = { repos: [] }; @@ -571,7 +559,7 @@ class RepoList extends Component { } } -export default RepoList; +export default App; ``` ## Integrating with a Node Backend From 8ec8ef04433576c79de6847ebb64ba3587dcc508 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Fri, 14 Oct 2016 20:19:23 -0700 Subject: [PATCH 6/7] Show error state and loading state --- packages/react-scripts/template/README.md | 154 ++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md index 268265bdb6d..0fe4382866c 100644 --- a/packages/react-scripts/template/README.md +++ b/packages/react-scripts/template/README.md @@ -24,6 +24,7 @@ You can find the most recent version of this guide [here](https://github.com/fac - [Adding Flow](#adding-flow) - [Adding Custom Environment Variables](#adding-custom-environment-variables) - [Can I Use Decorators?](#can-i-use-decorators) +- [Fetching AJAX Requests](#fetching-ajax-requests) - [Integrating with a Node Backend](#integrating-with-a-node-backend) - [Proxying API Requests in Development](#proxying-api-requests-in-development) - [Using HTTPS in Development](#using-https-in-development) @@ -542,6 +543,159 @@ Please refer to these two threads for reference: Create React App will add decorator support when the specification advances to a stable stage. +## Fetching AJAX Requests + +This project includes a [fetch polyfill](https://github.com/github/fetch), which makes it easier to make web requests. + +The global `fetch` function allows to easily makes AJAX requests. It takes in a URL as an input and returns a `Promise` that resolves to a `Response` object. You can find more information about `fetch` [here](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). + + +__About Promises:__ This project also includes a [Promise polyfill](https://github.com/then/promise) which provides a full implementation of Promises/A+. A Promise represents the eventual result of an asynchronous operation, you can find more information about Promises [here](https://www.promisejs.org/) and [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). + +You can make a GET request like this: +```javascript +import React, { Component } from 'react'; +import './App.css'; + +class App extends Component { + constructor(props) { + super(props); + this.state = { users: [] }; + } + + componentDidMount() { + this.fetchStargazers(); + } + + fetchStargazers() { + this.setState({ isLoading: true }); + fetch('https://api.github.com/repos/facebook/react/stargazers') + .then((response) => response.json()) + .catch(() => ({ message: 'Error while fetching stargazers' })) + .then((res) => { + if (!this.hasUnmounted) { + if (res.message) { + this.setState({ + isLoading: false, + error: res.message, + users: [], + }); + } else { + this.setState({ + isLoading: false, + error: null, + users: res, + }); + } + } + }); + } + + componentWillUnmount() { + this.hasUnmounted = true; + } + + render() { + const { users, error, isLoading } = this.state; + + if (isLoading) { + return ( +
+

Loading...

+
+ ); + } + + return ( +
+
    +

    {error}

    + {users.map((user) => ( +
  • + {user.login} +
  • + ))} +
+
+ ); + } +} + +export default App; +``` + +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 +import React, { Component } from 'react'; +import './App.css'; + +class App extends Component { + constructor(props) { + super(props); + this.state = { users: [] }; + } + + componentDidMount() { + this.fetchStargazers(); + } + + async fetchStargazers() { + let error; + let users; + + this.setState({ isLoading: true }); + + try { + const response = await fetch('https://api.github.com/repos/facebook/react/stargazers'); + const body = await response.json(); + if (body.message) { + error = body.message; + } else { + users = body; + } + } catch (e) { + error = 'Error while fetching stargazers'; + users = []; + } + + if (!this.hasUnmounted) { + this.setState({ isLoading: false, error, users }); + } + } + + componentWillUnmount() { + this.hasUnmounted = true; + } + + render() { + const { users, error, isLoading } = this.state; + + if (isLoading) { + return ( +
+

Loading...

+
+ ); + } + + return ( +
+
    +

    {error}

    + {users.map((user) => ( +
  • + {user.login} +
  • + ))} +
+
+ ); + } +} + +export default App; +``` + ## Integrating with a Node Backend Check out [this tutorial](https://www.fullstackreact.com/articles/using-create-react-app-with-a-server/) for instructions on integrating an app with a Node backend running on another port, and using `fetch()` to access it. You can find the companion GitHub repository [here](https://github.com/fullstackreact/food-lookup-demo). From d998dde91d704fe3064705ba9fa59ddb44ca8c90 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Fri, 14 Oct 2016 20:45:26 -0700 Subject: [PATCH 7/7] Modify example to use response.ok --- packages/react-scripts/template/README.md | 43 ++++++++++++----------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md index 0fe4382866c..60601b4fe6a 100644 --- a/packages/react-scripts/template/README.md +++ b/packages/react-scripts/template/README.md @@ -561,6 +561,7 @@ class App extends Component { constructor(props) { super(props); this.state = { users: [] }; + this.defaultError = 'Error while fetching stargazers'; } componentDidMount() { @@ -570,23 +571,20 @@ class App extends Component { fetchStargazers() { this.setState({ isLoading: true }); fetch('https://api.github.com/repos/facebook/react/stargazers') - .then((response) => response.json()) - .catch(() => ({ message: 'Error while fetching stargazers' })) - .then((res) => { + .then((response) => { + const body = response.json(); + if (response.ok) { + return body.then((users) => ({ users })); + } + + return body.then(({ message }) => ( + { users: [], error: message || this.defaultError } + )); + }) + .catch(() => ({ users: [], error: this.defaultError })) + .then(({ users, error }) => { if (!this.hasUnmounted) { - if (res.message) { - this.setState({ - isLoading: false, - error: res.message, - users: [], - }); - } else { - this.setState({ - isLoading: false, - error: null, - users: res, - }); - } + this.setState({ isLoading: false, error, users }); } }); } @@ -633,6 +631,7 @@ class App extends Component { constructor(props) { super(props); this.state = { users: [] }; + this.defaultError = 'Error while fetching stargazers'; } componentDidMount() { @@ -647,14 +646,16 @@ class App extends Component { try { const response = await fetch('https://api.github.com/repos/facebook/react/stargazers'); - const body = await response.json(); - if (body.message) { - error = body.message; + + if (response.ok) { + users = await response.json(); } else { - users = body; + const body = await response.json(); + error = body.message || this.defaultError; + users = []; } } catch (e) { - error = 'Error while fetching stargazers'; + error = this.defaultError; users = []; }