https://www.algolia.com

Build Unique Search ExperiencesHosted Search API that delivers instant and relevant results from the first keystroke

1

1

1

1

https://classroom.udacity.com/nanodegrees/nd019-cn-preview/parts/27705889-df26-448f-afa2-4d316d589128/modules/4885698c-c850-41a0-86f7-92cbdb0b75f9/lessons/9a065aa0-91d4-44a3-ad96-8d9b44be4d11/concepts/a4123f05-9331-4144-8a25-36949c80f22a

函数组合的优势

因为函数组合是让 React 非常强大的重要原因之一,因此我们将深入了解这一概念。注意,函数组合就是将简单的函数组合到一起,并形成复杂的函数。有几个重要概念值得注意,包括:

  • 简单的函数
  • 组合到一起形成另一个函数

函数组合由简单的函数构成。我们看一个示例:

function getProfileLink (username) {
return 'https://github.com/' + username
}

这个函数极为简单,对吧?只有一行!类似地,getProfilePic 函数只有一行:

function getProfilePic (username) {
return 'https://github.com/' + username + '.png?size=200'
}

这些函数绝对是简单的函数,要组合它们,我们将它们放进另一个函数中:

function getProfileData (username) {
return {
pic: getProfilePic(username),
link: getProfileLink(username)
}
}

我们可以不用组合形成 getProfileData,而是直接向其提供数据:

function getProfileData (username) {
return {
pic: 'https://github.com/' + username + '.png?size=200',
link: 'https://github.com/' + username
}
}

理论上来说,根本没有问题;这完全是正确的 JavaScript 代码。但不是函数组合。这个不使用组合的版本还可能存在几个问题。如果要在其他地方需要用户的 GitHub 链接,那么可能需要重复的代码。好的函数应该遵守"DOT”规则:

只做一件事

这个函数做了好几件事(无论有多小);创建两个不同的 URL,将它们存储为对象上的某个属性,然后返回该属性。在组合版本中,每个函数只做一件事:

  • getProfileLink – 只构建用户的 GitHub 个人资料链接字符串
  • getProfilePic – 只构建用户的 GitHub 个人资料照片字符串
  • getProfileData – 返回新的对象
 

React 与函数组合

React 频繁利用函数组合!React 使用组件构建 UI 的各个部分。我们看看一些伪代码示例。以下是三个不同的组件:

<Page />
<Article />
<Sidebar />

现在我们将这些简单的组件组合到一起,并创建更复杂的组件(又叫做 组合action!):

<Page>
<Article />
<Sidebar />
</Page>

现在,Page 组件里面具有 Article 和 Sidebar 组件。就像之前的示例那样,getProfileData 里具有 getProfileLink 和 getProfilePic

稍后我们将讲解组件,暂时先记住组合在构建 React 组件的过程中发挥了很大的作用。

 

函数组合总结

函数组合是指将简单的函数组合到一起并形成更复杂的函数。可以将每个函数看做一个只做一件事 (DOT)的构建模块。当你将这些简单的函数组合到一起并形成更复杂的函数时,这就叫做函数组合

https://www.linkedin.com/pulse/compose-me-function-composition-javascript-kevin-greene/

https://ramdajs.com/0.21.0/index.html

https://github.com/ramda/ramda

https://hackernoon.com/javascript-functional-composition-for-every-day-use-22421ef65a10

***

命令式代码

很多 JavaScript 都是命令式代码。如果你不知道这里的“命令式”是什么意思,那么可能会比较头疼。根据字典的定义,“命令式”是指:

表示一项命令;下达命令

如果将 JavaScript 代码写成命令式,则我们是在明确地告诉 JavaScript 做什么,如何执行。可以看做我们命令 JavaScript 明确执行哪些步骤。例如,下方的一个简单 for 循环:

const people = ['Amanda', 'Geoff', 'Michael', 'Richard', 'Ryan', 'Tyler']
const excitedPeople = [] for (let i = 0; i < people.length; i++) {
excitedPeople[i] = people[i] + '!'
}

如果你以前接触过 JavaScript(无论多久),那么这段代码应该好理解。我们循环访问 people 数组中的每项,向他们的名称中添加一个感叹号,并将新字符串存储到 excitedPeople 数组中。很简单吧?

但这是命令式代码。我们命令 JavaScript 在每一步执行什么操作。我们需要给它下达命令:

  • 为迭代器设定初始值 - (let i = 0)
  • 告诉 for 循环何时停止 - (i < people.length)
  • 获得当前位置的用户并添加一个感叹号 - (people[i] + '!')
  • 将 ith 位置的数据存储到另一个数组中 - (excitedPeople[i])
  • 使 i 变量加一 - (i++)

还记得使气温保持 22º 的示例吗?我会转动旋钮以吹出冷气。但是如果太冷的话,我就将旋钮拧的更高。最终,会变得太热,我需要再次将旋钮拧低些。我需要一点点地改变,自己管理温度。听起来像命令式情形吗?我需要手动执行多个步骤。不理想,因此改善下吧!

 

声明式代码

与命令式代码相反的是声明式代码。对于声明式代码,我们不编写所有步骤来获得最终结果。相反,我们声明要完成的操作,JavaScript 将帮助我们执行它。这种解释有点抽象,我们来看个示例。我们将刚刚查看的命令式 for循环代码变得更加声明式。

对于命令式代码,我们执行所有步骤来获得最终结果。但是,我们实际上希望达到什么样的最终结果?起始点是名称数组:

const people = ['Amanda', 'Geoff', 'Michael', 'Richard', 'Ryan', 'Tyler']

最终目标是名称保持不变,但是每个名称结尾处都有一个感叹号:

["Amanda!", "Geoff!", "Michael!", "Richard!", "Ryan!", "Tyler!"]

要从起点抵达终点,我们将使用 JavaScript 的 .map() 函数声明我们想要的结果。

const excitedPeople = people.map(name => name + '!')

就是这样!注意,对于这段代码,我们没有:

  • 创建迭代器对象
  • 告诉代码何时应该停止运行
  • 使用迭代器访问 people 数组中的特定项
  • 将每个新字符串存储在 excitedPeople 数组中

...所有这些步骤都由 JavaScript 的 .map() 数组方法来完成。

 

练习题

下面的代码是命令式还是声明式?

const people = ['Amanda', 'Geoff', 'Michael', 'Richard', 'Ryan', 'Tyler']
const longNames = people.filter(name => name.length > 6)
  • 命令式

  • 声明式

提交
 

.map() 和 .filter()

已经快忘记 JavaScript 的 .map() 和 .filter() 数组方法了?或者你就从未接触过这两个方法。无论何种情况,我们都将在 React “就是 JavaScript” 部分深入讲解这两个方法。继续学习吧!

 

React 是声明式

我们很快就会编写 React 代码,先再看一段示例,了解它为何是声明式。

<button onClick={activateTeleporter}>Activate Teleporter</button>

你可能觉得奇怪,但这段代码是有效的 React 代码,应该很容易理解。注意,按钮只有一个 onClick 属性... 我们没有使用 .addEventListener() 并利用所有涉及的步骤来设置事件处理过程。我们只是声明我们希望在按钮被点击时,运行 activateTeleporter 函数。

 

声明式代码总结

命令式代码告诉 JavaScript 如何执行每个步骤。对于声明式代码,我们告诉 JavaScript 我们希望实现什么结果,让 JavaScript 处理每个步骤。

React 是声明式代码,因为我们编写代码来声明我们想要什么,React 负责处理声明的代码,并执行所有的 JavaScript/DOM 步骤来实现我们期望的结果。

React 中的数据流总结

在 React 中,数据仅朝一个方向流动,即从父组件流向子组件。如果数据在兄弟子组件之间共享,那么数据应该存储在父组件中,并同时传递给需要数据的两个子组件。

就是 JavaScript

React 的优势之一是你要用到的很多功能都使用的是普通的 JavaScript。在过去几年内,函数式编程对 JavaScript 生态系统和社区产生了很大的影响。函数式编程是 JavaScript 中一个高级课题,涉及的内容用数百本书才能讲完。它太复杂了,以至于无法专研函数式编程的优势(我们还是要讲解 React 内容吧?)。React 基于的是大量的函数式编程的技巧…你将在这门课程中学习这些技巧。但是,有几个 JavaScript 函数对函数式编程来说非常重要,我们应该了解这些函数。这些函数包括 .map() 和 .filter() 方法。

我们详细了解下 .map() 和 .filter() 数组方法。

 

Array 的 .map() 方法

如果你不熟悉 JavaScript 的 Array .map() 方法 的话,其实它是在现有的数组上被调用,然后根据当做参数传入的函数返回的内容返回新的数组。我们看看:

const names = ['Michael', 'Ryan', 'Tyler'];

const nameLengths = names.map( name => name.length );

看看发生了什么情况。.map() 方法适用于数组,因此首先要有数组:

const names = ['Michael', 'Ryan', 'Tyler'];

我们针对 names 数组调用 .map() 并传入一个函数作为参数:

names.map( name => name.length );

names 数组中的每一项都会调用传递给 .map() 的箭头函数!箭头函数接收数组中的第一个名称,将其存储在变量 name 中,并返回其长度。然后对剩下的两个名称执行相同的操作。

.map() 返回新的数组,该新数组的每一项都是箭头函数所返回的值:

const nameLengths = names.map( name => name.length );

因此 nameLengths 将为新的数组 [7, 4, 5]。一定要理解这一点;.map() 方法返回新的数组,它没有修改原始数组。

上面只是简单地介绍了 .map() 方法的运行原理。要深入了解该方法,请访问 MDN 上的 .map()

 

.map() 测验

使用提供的音乐数据数组和 .map() 方法创建一个新的数组,并包含以下格式的元素:

<album> by <name> sold <sales> copies

将新数组存储在 albumSalesStrings 数组中。因此 albumSalesStrings 数组中的第一项应该是 "25 by Adele sold 1731000 copies"

```js
 
/* Using .map()
*
* Using the musicData array and .map():
* - return a string for each item in the array in the following format
* <album-name> by <artist> sold <sales> copies
* - store the returned data in a new albumSalesStrings variable
*
* Note:
* - do not delete the musicData variable
* - do not alter any of the musicData content
* - do not format the sales number, leave it as a long string of digits
*/
 
const musicData = [
{ artist: 'Adele', name: '25', sales: 1731000 },
{ artist: 'Drake', name: 'Views', sales: 1608000 },
{ artist: 'Beyonce', name: 'Lemonade', sales: 1554000 },
{ artist: 'Chris Stapleton', name: 'Traveller', sales: 1085000 },
{ artist: 'Pentatonix', name: 'A Pentatonix Christmas', sales: 904000 },
{ artist: 'Original Broadway Cast Recording',
name: 'Hamilton: An American Musical', sales: 820000 },
{ artist: 'Twenty One Pilots', name: 'Blurryface', sales: 738000 },
{ artist: 'Prince', name: 'The Very Best of Prince', sales: 668000 },
{ artist: 'Rihanna', name: 'Anti', sales: 603000 },
{ artist: 'Justin Bieber', name: 'Purpose', sales: 554000 }
];
 
const albumSalesStrings = 'Replace this message with your code!';
 
console.log(albumSalesStrings);
 
 ```

Map 方法测验解决方案代码

自己尝试解答这道测验后,请将光标悬停在此处以查看可行的解决方案。
 

Array 的 .filter() 方法

JavaScript 的 Array .filter() 方法 和 .map() 方法相似:

  • 在数组上被调用
  • 传入函数作为参数
  • 返回新的数组

区别在于传递给 .filter() 的函数用作检验条件,数组中只有通过检验的项目才会包含在新数组中。我们看一个示例:

const names = ['Michael', 'Ryan', 'Tyler'];

const shortNames = names.filter( name => name.length < 5 );

和之前一样,起始数组如下:

const names = ['Michael', 'Ryan', 'Tyler'];

我们对 names 数组调用 .filter() 并向其传递一个函数作为参数:

names.filter( name => name.length < 5 );

和 .map() 一样,names 数组中的每一项都会调用传递给 .filter() 的箭头函数。第一项(即 'Michael')存储在 name 变量中。然后进行检验,也就是进行实际的过滤操作。它会检查名称的长度,如果大于等于 5,那么就跳过该名称(并且不包含在新数组中!)。但是,如果名称的长度小于 5,那么 name.length < 5 返回 true 并且该名称包含在新数组中!

最后,和 .map() 一样,.filter() 方法返回新的数组,而不是修改原始数组:

const shortNames = names.filter( name => name.length < 5 );

因此 shortNames 将为新数组 ['Ryan']。注意,现在它里面只有一个名称,因为 'Michael' 和 'Tyler' 都是 5个字符或更长,被滤除了。

上面只是简单地介绍了 .filter() 方法的运行原理。要深入了解该方法,请访问 MDN 上的 .filter()

 

.filter() 测验

使用提供的音乐数据数组和 .filter() 方法创建一个新的数组,其中仅包含名称在 10 和 25 个字符之间的专辑。将新数组存储在变量 results 中。

 ```js
 
/* Using .filter()
*
* Using the musicData array and .filter():
* - return only album objects where the album's name is
* 10 characters long, 25 characters long, or anywhere in between
* - store the returned data in a new `results` variable
*
* Note:
* - do not delete the musicData variable
* - do not alter any of the musicData content
*/
 
const musicData = [
{ artist: 'Adele', name: '25', sales: 1731000 },
{ artist: 'Drake', name: 'Views', sales: 1608000 },
{ artist: 'Beyonce', name: 'Lemonade', sales: 1554000 },
{ artist: 'Chris Stapleton', name: 'Traveller', sales: 1085000 },
{ artist: 'Pentatonix', name: 'A Pentatonix Christmas', sales: 904000 },
{ artist: 'Original Broadway Cast Recording',
name: 'Hamilton: An American Musical', sales: 820000 },
{ artist: 'Twenty One Pilots', name: 'Blurryface', sales: 738000 },
{ artist: 'Prince', name: 'The Very Best of Prince', sales: 668000 },
{ artist: 'Rihanna', name: 'Anti', sales: 603000 },
{ artist: 'Justin Bieber', name: 'Purpose', sales: 554000 }
];
 
const results = 'Replace this message with your code!';
 
console.log(results);
 
 
 
```

Filter 测验解决方案代码

自己尝试解答这道测验后,请将光标悬停在此处以查看可行的解决方案。
 

将 .map() 和 .filter() 组合到一起

.map() 和 .filter() 的如此强大之处在于它们可以组合到一起。因为两个方法都返回数组,因此我们可以将它们的方法调用链到一起,一个方法返回的数据可以是另一个方法的新数组。

const names = ['Michael', 'Ryan', 'Tyler'];

const shortNamesLengths = names.filter( name => name.length < 5 ).map( name => name.length );

详细讲解下,names 数组被过滤,并返回新的数组,然后对该新数组调用 .map(),并再次返回新的数组!.map() 返回的新数组存储在 shortNamesLengths 中。

首先是 .filter()

提醒下,你需要按照一定的顺序组合二者(先是 .filter(),然后是 .map())。因为 .map() 针对数组中的每项都调用一次函数,因此如果数组已经过滤过的话,运行速度会更快。

 

.filter() 和 .map() 测验

使用同一音乐数据和 .filter() 及 .map() 来过滤并映射列表,将结果存储在变量 popular 中。使用 .filter() 从列表中过滤出销量超过 1,000,000 张的专辑。然后对返回的数组调用 .map(),并创建一个项目格式如下的新数组:

<artist> is a great performer

popular 数组中的第一项将为 'Adele is a great performer'

```js
 
/* Combining .filter() and .map()
*
* Using the musicData array, .filter, and .map():
* - filter the musicData array down to just the albums that have
* sold over 1,000,000 copies
* - on the array returned from .filter(), call .map()
* - use .map() to return a string for each item in the array in the
* following format: "<artist> is a great performer"
* - store the array returned form .map() in a new "popular" variable
*
* Note:
* - do not delete the musicData variable
* - do not alter any of the musicData content
*/
 
const musicData = [
{ artist: 'Adele', name: '25', sales: 1731000 },
{ artist: 'Drake', name: 'Views', sales: 1608000 },
{ artist: 'Beyonce', name: 'Lemonade', sales: 1554000 },
{ artist: 'Chris Stapleton', name: 'Traveller', sales: 1085000 },
{ artist: 'Pentatonix', name: 'A Pentatonix Christmas', sales: 904000 },
{ artist: 'Original Broadway Cast Recording',
name: 'Hamilton: An American Musical', sales: 820000 },
{ artist: 'Twenty One Pilots', name: 'Blurryface', sales: 738000 },
{ artist: 'Prince', name: 'The Very Best of Prince', sales: 668000 },
{ artist: 'Rihanna', name: 'Anti', sales: 603000 },
{ artist: 'Justin Bieber', name: 'Purpose', sales: 554000 }
];
 
const popular = 'Replace this message with your code!';
 
 
 
 ```

Filter & Map 测验解决方案代码

自己尝试解答这道测验后,请将光标悬停在此处以查看可行的解决方案。
 

React 就是 JavaScript 总结

React 是在你已经了解的 JavaScript 基础上构建而成的!你不需要学习特殊的模板库或新的执行方式。

你将经常用的两个主要方法是:

请务必熟练使用这两个方法,请花些时间练习使用它们。不妨查看你的一些现有代码并尝试将你的 for 循环转换为 .map() 调用,或者看看是否能够使用 .filter() 删除任何 if 语句。

> React 使用 JavaScript 对象来创建 `React 元素`。我们将使用这些 React 元素来描述我们希望页面看起来如何,React 将负责`生成 DOM 节点`来达到效果。

还记得在上节课提到的命令式与声明式代码之间的区别吗?我们编写的 React 代码是声明式,因为我们没有告诉 React 执行什么操作;我们编写 React 元素来描述页面应该看起来怎么样,React 会执行所有的实现工作。

在 DOM 上渲染元素

在上个视频中,我们使用 ReactDOM 的 render() 方法将我们的元素渲染到页面的特定区域。具体而言,我们在叫做 root 的 DOM 节点上渲染了 element。这个 root 来自哪里?

使用 React 构建的应用通常有一个 root DOM 节点。例如,一个 HTML 文件可能包含以下 <div>

<div id='root'></div>

通过将该 DOM 节点传入 getElementById(),React 将最终能够控制它的所有内容。另一种思考方法是这个 <div> 将充当我们 React 应用的“钩子”;React 将控制该区域并渲染我们的 UI!

> React 的 .createElement() 方法获得元素的说明并返回简单的 JavaScript 对象。

https://doc.react-china.org/docs/dom-elements.html#%E6%89%80%E6%9C%89%E5%8F%97%E6%94%AF%E6%8C%81%E7%9A%84html%E5%B1%9E%E6%80%A7

值得注意的一点是,你无法使用默认的 for 属性。就像你需要使用 className而不是 class,你需要使用 htmlFor 而不是 for。这是因为 'for' 是 JavaScript 的保留词。

我刚刚使用 React 的 .createElement() 方法构建了一个 “React 元素”。.createElement() 方法具有以下方法:

React.createElement( /* type */, /* props */, /* content */ );

我们详细分析每一项参数可以为:

  • type – 字符串或 React 组件

    可以是任何现有 HTML 元素字符串(例如 ‘p’‘span’ 或 ‘header’),或者你可以传递 React 组件(稍后我们将使用 JSX 创建组件)。

  • props – 为 null 或一个对象

    这是 HTML 属性的对象以及关于该元素的自定义数据。

  • content – null、字符串、React 元素或 React 组件

    你在此处传递的任何内容都将为所渲染元素的内容。包括纯文本、JavaScript 代码、其他 React 元素等。

### unique key

.createElement() 返回一个根元素

React.createElement( /* type */, /* props */, /* content */ ); 创建一个特定类型的 React 元素。我们通常会传入一个标签,例如 <div> 或 <span> 来表示该类型,但是内容参数可以是另一个 React 元素!

看看下面的示例:

const element = React.createElement('div', null,
React.createElement('strong', null, 'Hello world!')
);

这里,当此 React 元素渲染为 HTML 时,"Hello world!"将包裹在 <div> 内。虽然我们可以嵌套 React 元素,但是注意整个调用仅返回一个元素。

## JSX

无论是 JSX 还是普通的 JavaScript(使用 createElement()),两个示例都生成了相同的 HTML:

JSX 也返回一个根元素

在编写 JSX 时,请记住,它只能返回一个元素。该元素可以有任何数量的子元素,但是只能有一个根元素封装整体 JSX (通常是一个 <div> 或 <span>)。请看看下面的示例:

const message = (
<div>
<h1>All About JSX:</h1>
<ul>
<li>JSX</li>
<li>is</li>
<li>awesome!</li>
</ul>
</div>
);

注意到上述代码中只有一个 <div> 元素,其他所有 JSX 都嵌套在其中了吗?如果你想要多个元素,就应该这么编写。为了完全弄明白这一点,下面的示例不正确,将导致错误:

const message = (
<h1>All About JSX:</h1>
<ul>
<li>JSX</li>
<li>is</li>
<li>awesome!</li>
</ul>
);

在此示例中,我们有两个兄弟元素,它们都在根级别(即 <h1> 和 <ul>)。这样是不可行的,会产生错误。

Syntax error: Adjacent JSX elements must be wrapped in an enclosing tag

因为我们知道 JSX 只是 .createElement() 的语法扩展,因此是合理的;.createElement() 只获得一个标签名称(字符串)作为其第一个参数。

 

组件简介

到目前为止,我们已经看到 .createElement() 和 JSX 可以帮助我们生成一些 HTML。但是,通常我们将使用 React 的主要功能之一来构建 UI:组件。组件是指可以重复利用的代码段,最终负责返回要渲染到网页上的 HTML。很多时候,你将看到用 JSX 编写的 React 组件。

因为 React 的侧重点是简化应用的 UI 构建过程,因此在任何 React 组件类中,只有一个方法是必须的:render()

我们开始构建我们的首个组件类吧!

在 React 中声明组件

在上个视频中,我们按以下方式定义了 ContactList 组件:

class ContactList extends React.Component {
// ...
}

换句话说,我们定义了一个其实是 JavaScript 类并且继承自 React.Component的组件。

在实际使用中(以及这门课程中),你可能还会看到下面的声明:

class ContactList extends Component {
// ...
}

两种方法的功能是一样的,但是确保你的模块导入部分能匹配!即,如果你选择像第二个示例那样声明组件,则 React 导入应该如下所示:

import React, { Component } from 'react';
 

创建元素总结

最后,记住 React 仅关心应用的 View 层级。这是用户能看见和互动的层级。因此,我们可以使用 .createElement() 向文档中渲染 HTML。但是更多时候,你将使用语法扩展来描述 UI 的外观应该如何。这种语法扩展称之为 JSX,看起来和编写在 JavaScript 文件中的普通 HTML 很像。JSX 编译为调用 React 的 .createElement() 方法,并输出要在浏览器中渲染的 HTML。

在构建 React 应用时一个便利的思维方式是React理念|(翻译链接)。组件代表的是 React 的模块性和可重复利用性。可以将组件类看做生成组件实例的工厂。这些组件类应该遵守单一功能原则,只做一件事。如果管理太多不同的任务,建议将组件拆分为更小的子组件。

课外资料:

https://zh.wikipedia.org/wiki/%E5%8D%95%E4%B8%80%E5%8A%9F%E8%83%BD%E5%8E%9F%E5%88%99

搭建 React 应用框架

JSX 很棒,但是它需要反编译为普通的 JavaScript,然后才能提交给浏览器。我们通常使用 Babel 等转译器来为我们实现转译。我们可以通过构建工具运行 Babel,例如 Webpack,它可以帮助我们打包Web项目的所有资源(JavaScript 文件、CSS、图片等)。

为了简化这一初始配置过程,我们可以使用 Facebook 的 Create React App 包来为我们实现所有设置!该工具非常实用,可以帮助我们开始构建 React 应用,因为它为我们设置了一切,我们无需进行任何配置!请 (通过 npm命令行)安装 Create React App,然后我们将讲解它的强大之处。

npm install -g create-react-app

当你试图安装一个全局的 package 但是出现报错时,可以查看一下 这篇文章。注意,想要找出这些全局软件包安装在哪儿,可以在终端运行npm list -g 查看(更多信息这里)。

https://github.com/udacity/reactnd-contacts-complete/commit/86824dc9f726e68a516f8cf85243b013a3b5c8b7

https://github.com/udacity/reactnd-contacts-complete

Yarn Package Manager

在下面的视频和 create-react-app 输出中,我们都需要使用 yarn start 来启动开发服务器。如果你从未听说过 Yarn,它就是一个类似于 NPM 的软件包管理器。Yarn 完全由 Facebook 创建而成,旨在改善 NPM 比较缓慢或缺少的关键部分。

如果你不想安装 Yarn,也没问题!它的强大之处在于每个 yarn 使用情况都可以替换为 npm,一切还是正常运行!因此,如果命令是 yarn start,你可以使用 npm start 来运行同一命令。

观察力强的学员可能注意到了,我的 index.js 文件不包含你的项目中出现的 registerServiceWorker();这一行。在我录完此视频之后,Create React App 的新版本添加了对 Service Worker 的调用。因为我们在此项目中不使用 Service Workers,因此没有任何影响。但是如果你想删掉,也可以!

 

create-react-app 总结

Facebook 的 create-react-app 是一个可以帮助构建 React 应用的命令行工具。借助该工具,就无需配置 Webpack 等模块打包工具,或者 Babel 等转译器。它们使用 create-react-app 进行预配置(并且隐藏起来),使你能够立即构建应用!

请点击以下链接,详细了解 create-react-app

## ACE

> demo

https://codepen.io/xgqfrms/full/XqvNrv/

![](https://images2018.cnblogs.com/blog/740516/201805/740516-20180526185348844-537062924.png)

最新文章

  1. iOS---观察者模式之---&gt;KVO
  2. HTML 学习笔记 CSS3(Animation)
  3. 解决WordPress中无法将上传的文件移动至wp-content/uploads
  4. Android IOS WebRTC 音视频开发总结(四十)-- 国内webrtc现状
  5. 【c++内存分布系列】单继承
  6. Linux更改默认jdk
  7. Hive Metastore 代码简析
  8. Ubuntu 13.04下安装Vmware tools 9.2.3
  9. PHP5.6通过CURL上传图片@符无效的兼容问题
  10. 高精度运算专题2-减法运算(The subtraction operation)
  11. hdu2709 Sumsets 递推
  12. ASP.NET导出word实例
  13. C语言求n的阶乘(n!)
  14. (一 ) 天猫精灵接入Home Assistant-服务器搭建
  15. PropertyPlaceholderConfigurer
  16. VMware虚拟机下Linux系统的全屏显示
  17. ASP.NET 网站超时跳转到登录界面
  18. 有趣的NaN类型
  19. 【bzoj4337】【Bjoi2015】树的同构
  20. ubuntu-12.04.5-desktop-amd64.iso:ubuntu-12.04.5-desktop-amd64:安装Oracle11gR2

热门文章

  1. 页面切换提速30%!京东商城APP首屏耗时监控及优化实践
  2. : cannot validate certificate for 127.0.0.1 because it doesn&#39;t contain any IP SANs
  3. 可视化Go内存管理
  4. py, pyc, pyw, pyo, pyd Compiled Python File (.pyc) 和Java或.NET相比,Python的Virtual Machine距离真实机器的距离更远
  5. epoll在fork子进程中的问题
  6. 在Ubuntu安装kubernetes
  7. Java学习路线图()
  8. PHP-表单提交(form)
  9. Commons Collections1分析
  10. 在线工具生成接入信息mqtt.fx快速接入阿里云