当我刚开始学习JavaScript
的时候,我就听说了React
,但我承认看了它一眼,它吓到我了。我看到了看起来一堆HTML
和CSS
的混合思想,这不是我们一直努力避免的事情吗?React有什么了不起的?
相反,我只专注于学习原始的JavaScript
,并在需要的时候使用jQuery
。经过几次失败的React
入门尝试之后,我终于开始了解它了,我开始明白为什么我可能想使用React
而不是原始的JS
或jQuery
。
我试图将自己学到的内容浓缩成一个很好的介绍,以便与你分享,下面就是~
预备知识
在开始学习React
之前,你应该事先了解一些事情。例如,如果你之前从没接触过JavaScript
或者DOM
,那么在解决React
之前,你要更加熟悉它们。
下面是我认为学习React
的预备知识:
- 熟悉 HTML & CSS的基础知识
- JavaScript 和编程的基础知识
- 对DOM有基本了解
- 熟悉 ES6 语法和特性
- 全局安装了Node.js 和 npm
目标
- 了解基本的
React
概念和相关术语,例如Babel
,Webpack
,JSX
,组件,属性,状态和生命周期 - 通过构建一个非常简单的
React
应用程序,以演示上面的概念。
下面是最终的相关源代码和示例。
- View Source on GitHub
- View Demo
React是什么?
-
React
是一个JavaScript
库 - 最受欢迎的库之一,在GitHub上超过100,000星星。 -
React
不是一个框架(不像Angular
,定位是框架)。 -
React
是Facebook
的开源项目。 -
React
用于在前端构建用户界面UI
。 -
React
是MVC (Model View Controller)
应用的View
层。
React
的最重要的方面之一是可以创建类似于自定义、可复用的HTML
元素的组件,以快速有效地构建用户界面。React
还使用状态state和属性props来简化数据的存储和处理方式。
我们将在本文中介绍这些内容及其更多的内容,我们来开始吧。
安装
有几种安装React
的方法,我将向你展示两种,以便你更好地了解它地工作方式。
静态HTML文件
第一种方法不是安装React
的流行方法,也不是我们本教程其余部分的工作方式,但是如果你接触过jQuery
之类的库,这将很熟悉并易于理解。如果你不熟悉Webpack
,Babel
和Node.js
,那这将是种恐怖的入门方式。
让我们开始创建一个基本的index.html
文件。我们将在头部head
中加载三个CDN
资源 - React
,DOM
和Babel
。我们还将创建一个id
为root
的div
,最后,我们将创建一个脚本script
标签,你自定义的代码将存在于该标签中。
# index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Hello React!</title>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
// React code will go here
</script>
</body>
</html>
在编写本文的时,我加载的库是稳定版本的。
- React -
React
顶级API
- React DOM - 添加特定于
DOM
的方法 - Babel -
JavaScript
编辑器,使我们可以在旧的浏览器中使用ES6+
我们应用程序的入口点是root div
元素,该元素按惯例命名。你还会注意到text / babel
的脚本类型,这是使用Babel
所必需的。
现在,让我们编写React
的第一个模块代码。我们将使用ES6
类来创建一个名为App
的React
组件。
# index.html
class App extends React.Component {
//...
}
现在,我们将添加render()
方法,这是类组件中唯一需要的方法,用于渲染DOM
节点。
# index.html
class App extends React.Component {
render() {
return (
//...
);
}
}
在return
内部,我们将编写简单的看起来像HTML
元素的内容。请注意,我们不在此处返回字符串,因此请勿在元素周围使用引号。这称为JSX
,我们将很快对其进行详细了解。
# index.html
class App extends React.Component {
render() {
return <h1>Hello world!</h1>
}
}
最后,我们将使用React DOM
的render()
方法将我们创建的App
类渲染到HTML
的root
容器div
中。
# index.html
ReactDOM.render(<App />, document.getElementById('root'))
下面是index.html
中完整的代码。
# index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Hello React!</title>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class App extends React.Component {
render() {
return <h1>Hello world!</h1>
}
}
ReactDOM.render(<App />, document.getElementById('root'))
</script>
</body>
</html>
现在,如果你在浏览器上查看index.html
,将看到我们创建的呈现给DOM
的h1
标签。
太棒了!现在你完成了这一步,你可以看到React
并没有那么让人着迷。只是一些JavaScript
帮助教程库,我们将其加载到HTML
中。
我们出于演示目的完成了此操作,但是从这里开始,我们将使用另一种方式:Create React App
。
创建React App
我刚刚使用的是将JavaScript
库加载到静态HTML
页面中并动态渲染React
和Babel
的方法不是很有效,并很难维护。
幸运的是,Facebook
创建了Create React App,该环境预先配置了构建React
所需要的一切。它将创建一个实时开发服务器,使用webpack
自动编译React
,JSX
和ES6
,自动为CSS
文件加前缀,并使用ESLint
测试和警告代码中的错误。
要设置create-react-app
,你要在终端运行以下代码,该代码位于你希望项目所在的目录。请确保你安装了5.2
以上版本的Node.js
。
npx create-react-app react-tutorial
安装完成之后,移至新创建的目录并启动项目。
cd react-tutorial
npm start
运行此命令之后,新的React
应用程序将在浏览器的localhost:3000
弹出一个新窗口。
如果你查看项目结构,将会看到/public
和/src
目录,以及常规的node_modules
,.gitignore
,README.md
和package.json
。
在/public
中,我们的重要文件是index.html
,它与我们之前制作的静态index.html
文件非常类似 - 只是一个root div
。这次,没有库或脚本被加载。/src
目录将包含我们所有的React
代码。
要查看环境如何自动编译和更新你的React
代码,请在/src/App.js
中查找如下所示的行:
To get started, edit `src/App.js` and save to reload.
然后将其替换为其他文本。保存文件后,你会注意到localhost:3000
页面会自动编译并刷新数据。
继续并删除/src
目录中的所有文件,我们将创建自己的样板文件,而不至于臃肿。我们只保留index.css
和index.js
。
对于index.css
,我只是将原始Primitive CSS 的内容复制并粘贴到文件中。如果需要,可以使用Bootstrap
或所需的任何CSS
框架,或者什么都不用。我只是觉得更容易使用而已。
在index.js
中,我引入了React
,ReactDOM
和CSS
文件。
# src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
让我们再次创建我们的App
组件。以前,我们只有一个<h1>
,但是现在我还要添加一个带有类的div
元素。你会注意到,我们使用的是className
而不是class
。这是我们的第一个提示,此处编写的代码是JavaScript
,而不是HTML
。
# src/index.js
class App extends Component {
render() {
return (
<div className="App">
<h1>Hello, React!</h1>
</div>
)
}
}
最后,我们像之前一样渲染App
到根节点中。
# src/index.js
ReactDOM.render(<App />, document.getElementById('root'))
下面是完整的index.js
代码。这次,我们将Component
加载为React
的属性,因此我们不再需要扩展React.Component
。
# src/index.js
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'
class App extends Component {
render() {
return (
<div className="App">
<h1>Hello, React!</h1>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
如果你回到localhost:3000
页面,像之前那样,你将会看到Hello, React!
字样。现在,我们已经开始了解React
应用程序了。
React开发者工具
有一个名为React Developer Tools
的扩展工具,可以使你在使用React
时的工作更加轻松。在你喜欢使用的任何浏览器中下载 React DevTools for Chrome。
安装后,当你打开DevTools
时,你将看到React
的标签。单击它,你将能够在编写组件时检查它们。你仍然可以转到elements
选项卡以查看实际的DOM
输出。现在看来似乎没什么大不了的,但是随着应用程序变得越来越复杂,使用它的必要性将越来越明显。
现在,我们拥有了实际开始使用React
所需的所有工具和安装设置。
JSX: JavaScript + XML
正如你所见,我们在React
代码中一直使用看起来像HTML
的东西,但是它并不是完全的HTML
。这是JSX,代表JavaScript XML
。
使用JSX
,我们可以编写类似HTML
的内容,也可以创建和使用自己的类似XML
的标签。下面是JSX
赋值给变量的样子。
# JSX
const heading = <h1 className="site-heading">Hello, React</h1>
编写React
并非必须使用JSX
。它在后台运行createElement
,它使用标签,包含属性的对象和子组件并呈现相同的信息。下面的代码具有和上面使用JSX
语法相同的输出。
# No JSX
const heading = React.createElement('h1', { className: 'site-heading' }, 'Hello, React!')
JSX
实际上更接近JavaScript
,而不是HTML
,因此在编写时需要注意一些关键区别。
- 因为
class
被作为JavaScript
中的保留关键字,className
用来替代class
添加CSS
类。 -
JSX
中的属性和方法是驼峰式的 -onclick
将变为onClick
- 自动闭合标签必须以斜杆结尾 - 例如
<img />
JavaScript
表达式也可以使用大括号将包括变量,函数和属性的内容嵌入JSX
中。
const name = 'Tania'
const heading = <h1>Hello, {name}</h1>
JSX
比原始的JavaScript
中创建和添加许多元素更容易编写和理解,这也是人们如此热爱React
的原因之一。
组件
到目前为止,我们创建了一个组件 - App
组件。React
中几乎所有内容都由组件组成,这些组件可以是类组件或简单组件。
大多数React
应用程序都是许多小组件,所有内容都加载到主要的App
组件中。组件也经常有自己的文件,因此让我们更改项目。
移除index.js
中的App
类,它现在长这样:
# src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import './index.css'
ReactDOM.render(<App />, document.getElementById('root'))
我们将创建一个名为App.js
的新文件,然后将组件放在那里。
# src/App.js
import React, { Component } from 'react'
class App extends Component {
render() {
return (
<div className="App">
<h1>Hello, React!</h1>
</div>
)
}
}
export default App
我们将组件导出为App
并将其加载到index.js
中。将组件分成文件不是强制性的,但是如果不这样做的话,应用程序将变得笨拙和混乱。
类组件
让我们创建另一个组件。我们将创建一个表格。创建一个Table.js
,并用以下数据填充它。
# src/Table.js
import React, { Component } from 'react'
class Table extends Component {
render() {
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
<tbody>
<tr>
<td>Charlie</td>
<td>Janitor</td>
</tr>
<tr>
<td>Mac</td>
<td>Bouncer</td>
</tr>
<tr>
<td>Dee</td>
<td>Aspiring actress</td>
</tr>
<tr>
<td>Dennis</td>
<td>Bartender</td>
</tr>
</tbody>
</table>
)
}
}
export default Table
我们创建的该组件是一个自定义类组件。我们大写自定义组件,以区别于常规HTML
元素。回到App.js
中,我们可以首先将Table
导入到其中:
# src/App.js
import Table from './Table'
然后通过将其加载到App
的render()
中,然后获得Hello, React!
。我还更改了外部容器的类。
# src/App.js
import React, { Component } from 'react'
import Table from './Table'
class App extends Component {
render() {
return (
<div className="container">
<Table />
</div>
)
}
}
export default App
如果你重新查看实际环境,则会看到Table
已加载。
现在,我们了解了什么是自定义类组件。我们可以反复使用此组件。但是,由于将数据硬编程(即写死)在其中,因此目前它并不太实用。
简单组件
React
中另外一种类型的组件就是简单组件,它是一个函数。该组件不使用class
关键字。让我们来看下Table
,我们将其拆分为两个简单的组件 - 表头和表体。
我们将使用ES6
箭头函数功能来创建这些简单的组件。首先是表头。
# src/Table.js
const TableHeader = () => {
return (
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
)
}
然后是表体:
# src/Table.js
const TableBody = () => {
return (
<tbody>
<tr>
<td>Charlie</td>
<td>Janitor</td>
</tr>
<tr>
<td>Mac</td>
<td>Bouncer</td>
</tr>
<tr>
<td>Dee</td>
<td>Aspiring actress</td>
</tr>
<tr>
<td>Dennis</td>
<td>Bartender</td>
</tr>
</tbody>
)
}
现在,我们Table
文件如下所示。请注意,TableHeader
和TableBody
组件都在同一个文件中,并且由Table
类组件使用。
# src/Table.js
const TableHeader = () => { ... }
const TableBody = () => { ... }
class Table extends Component {
render() {
return (
<table>
<TableHeader />
<TableBody />
</table>
)
}
}
之后,一切都像之前那样展示。如你所见,组件可以嵌套在其他组件中,并且简单组件和类组件可以混合使用。
一个类组件必须包括 render(),并且返回只能返回一个父组件。
作为总结,让我们来比较一个简单组件和一个类组件。
# Simple Component
const SimpleComponent = () => {
return <div>Example</div>
}
# Class Component
class ClassComponent extends Component {
render() {
return <div>Example</div>
}
}
请注意,如果return
的内容包含在一行中,则不需要括号。
Props属性
现在,我们有了一个很棒的Table
组件,但是数据正在被硬编码。关于React
的重要问题之一是如何处理数据,是通过属性(称为props)和状态(state)来处理数据。现在,我们将专注于使用props
来处理数据。
首先,我们将TableBody
组件的数据移除。
# src/Table.js
const TableBody = () => {
return <tbody />
}
然后,将所有数据移到对象数组中,就像我们引入基于JSON
的API
一样。我们必须在render()
内部创建此数组。
# src/App.js
class App extends Component {
render() {
const characters = [
{
name: 'Charlie',
job: 'Janitor',
},
{
name: 'Mac',
job: 'Bouncer',
},
{
name: 'Dee',
job: 'Aspring actress',
},
{
name: 'Dennis',
job: 'Bartender',
},
]
return (
<div className="container">
<Table />
</div>
)
}
}
现在,我们将通过属性将数据传递给子组件(Table
),这类似于使用数据data-
属性传递数据的方式。只要不是保留关键字,我们都可以随意调用该属性,因此我将使用characterData
。我传递的数据是Characters
变量,由于它是JavaScript
表达式,因此用大括号括起来。
# src/App.js
return (
<div className="container">
<Table characterData={characters} />
</div>
)
现在,数据已经传递给Table
,我们要做得是在另一边接收数据。
# src/Table.js
class Table extends Component {
render() {
const { characterData } = this.props
return (
<table>
<TableHeader />
<TableBody characterData={characterData} />
</table>
)
}
}
如果你打开React DevTools
,然后观测Table
组件,你将看到一个数组数据在其属性上。此处存储的数据称为虚拟DOM,这是一种将数据与实际DOM
同步快速有效的方法。
但是,此数据尚未在实际的DOM
中。在表格中,我们可以通过this.props
访问所有属性。我们仅传递一个属性characterData
,因此我们将使用this.props.characterData
来检索该数据。
我将使用ES6
属性的简写来创建一个包含this.props.characterData
的变量。
const { characterData } = this.props
因为,我们的Table
组件实际上由两个小的简单组件组成,因此我将再次通过props
将其传递给TableBody
。
# src/Table.js
class Table extends Component {
render() {
const { characterData } = this.props
return (
<table>
<TableHeader />
<TableBody characterData={characterData} />
</table>
)
}
}
现在,TableBody
不带任何参数并返回单个标签。
# src/Table.js
const TableBody = () => {
return <tbody />
}
我们将把props
作为参数传递,并通过map返回数组中每个对象的表行。该映射(map)将包含在rows
变量中,我们将其作为表达式返回。
# src/Table.js
const TableBody = props => {
const rows = props.characterData.map((row, index) => {
return (
<tr key={index}>
<td>{row.name}</td>
<td>{row.job}</td>
</tr>
)
})
return <tbody>{rows}</tbody>
}
如果你查看应用程序的前端,则所有的数据正在加载中。
你会注意到我已经向每个表行添加了一个键索引。在React
中创建列表时,应始终使用key(键),因为它们有助于识别每个列表项。我们还将在需要操纵列表项的时刻看到这是必要的。
Props
是将现有数据传递到React
组件的有效方法,但是该组件无法更改属性 - 它们是只读的。在下一节中,我们将学习如何使用state
来进一步控制React
中的数据处理。
state状态
现在,我们将字符数据存在变量的数组中,并将其作为props
传递。这是一个很好的开始,但是请想象下,如果我们希望能够从数组中删除一个项目。使用props
,我们有了一种单向数据流;但是有了状态state
,我们可以更新组件中的私有数据。
你可以将状态state
视为无需保存或修改,而不必添加到数据库中的任何数据 - 例如,在确认购买之前,在购物车中添加和删除商品。
首先,我们将创建一个状态state
对象。
# src/App.js
class App extends Component {
state = {}
}
该对象将包含你需要在状态中存储的所有内容属性。对我们来说,就是characters
。
# src/App.js
class App extends Component {
state = {
characters: [],
}
}
将我们之前创建的对象的整个数组移到state.characters
中。
# src/App.js
class App extends Component {
state = {
characters: [
{
name: 'Charlie',
// the rest of the data
},
],
}
}
我们的数据已正式包含在state
中。由于我们希望能够从表格中删除字符,因此我们将父App
类上创建removeCharacter
方法。
要检索状态,我们将使用与以前相同的ES6
方法获取this.state.characters
。要更新这个状态,我们使用this.setState()
,这是一种用于处理状态state
的内置方法。我们将根据传递的索引index
过滤filter数组,然后返回新数组。
你必须使用 this.setState() 修改数组。仅将新值应用于 this.state.propert 将不起作用
# src/App.js
removeCharacter = index => {
const { characters } = this.state
this.setState({
characters: characters.filter((character, i) => {
return i !== index
}),
})
}
filter
不会突变,而是创建一个新数组,并且是在JavaScript
中修改数组的首选方法。这种特殊的方法是测试索引与数组中的所有索引,并返回除传递的索引之外的所有索引。
现在,我们必须将该函数传递给组件,并在每个可以调用该函数的字符旁边绘制一个按钮。我们将removeCharacter
函数作为Table
的属性。
# src/App.js
render() {
const { characters } = this.state
return (
<div className="container">
<Table characterData={characters} removeCharacter={this.removeCharacter} />
</div>
)
}
由于我们将其从Table
传递到TableBody
,因此我们将不得不像props
一样再次将其作为属性传递。
另外,由于事实证明,在我们的项目中仅由其自己的状态的组件是App
和Form
,因此最佳实际是将Table
从当前的类组件转换为简单的组件。
# src/Table.js
const Table = (props) => {
const { characterData, removeCharacter } = props;
return (
<table>
<TableHeader />
<TableBody characterData={characterData} removeCharacter={removeCharacter} />
</table>
);
}
这就是我们在removeCharacter()
方法中定义的索引的输入位置。在TableBody
组件中,我们将key/index
作为参数传递,因此过滤器函数知道要删除项目。我们将创建一个带有onClick
的按钮并将其传递。
# src/Table.js
<tr key={index}>
<td>{row.name}</td>
<td>{row.job}</td>
<td>
<button onClick={() => props.removeCharacter(index)}>Delete</button>
</td>
</tr>
onClick 函数必须通过一个返回 removeCharacter() 方法的函数,否则它将尝试自动运行。
太棒了,现在我们有了删除按钮,我们可以通过删除字符来修改状态。
我删除了Mac
数据。
现在,你应该了解如何初始化状态以及如何修改状态了。
提交表单数据
现在,我们已经将数据存储在状态中,并且可以从状态中删除任何项目。但是,如果我们希望能够添加新数据来到状态呢?在现实世界的应用程序中,你更有可能从空状态开始添加,例如代办事项列表或购物车。
开始前,我们从state.characters
中删除所有的硬编码的数据,因此我们现在将通过表单进行更新。
# src/App.js
class App extends Component {
state = {
characters: [],
}
}
现在,让我们继续在一个名为Form.js
的新文件中创建一个Form
组件。我们将创建一个类组件,并在其中使用一个constructor()
,到目前为止,我们还没做过。我们需要constructor()
来使用它,并接收父项的props
。
我们将把Form
的初始状态设置为具有一些空属性的对象,并将该初始状态分配给this.state
。
# src/Form.js
import React, { Component } from 'react'
class Form extends Component {
constructor(props) {
super(props)
this.initialState = {
name: '',
job: '',
}
this.state = this.initialState
}
}
我们对此表单的目标是,每次在表单中更改字段时都会更新Form
的状态,并且在我们提交时,所有这些数据将传递到App
状态,然后App
状态将更新Table
。
首先,我们将使该函数在每次对输入进行更改时都将运行。event
将传递,我们将设置Form
的状态为输入name
(键)和value
(值)。
# src/Form.js
handleChange = event => {
const { name, value } = event.target
this.setState({
[name]: value,
})
}
在继续提交表单之前,我们需要这个运行起来。在渲染中,让我们从state
中获取两个属性,并将它们分配为正确的表单键对应的值。我们将把handleChange()
作为输入的onChange
运行,最后导出Form
组件。
# src/Form.js
render() {
const { name, job } = this.state;
return (
<form>
<label for="name">Name</label>
<input
type="text"
name="name"
id="name"
value={name}
onChange={this.handleChange} />
<label for="job">Job</label>
<input
type="text"
name="job"
id="job"
value={job}
onChange={this.handleChange} />
</form>
);
}
export default Form;
在App.js
中,我们可以在下表中渲染表单。
# src/App.js
return (
<div className="container">
<Table characterData={characters} removeCharacter={this.removeCharacter} />
<Form />
</div>
)
现在,如果我们转到应用程序的前端,将会看到尚未提交的表单。更新一些字段,你将看到正在更新的Form
的本地状态。
太棒了。最后一步是允许我们实际提交该数据并更新父状态。我们将在App
上创建一个名为handleSubmit()
的函数,该函数通过使用ES6扩展运算符获取现有的this.state.characters
并添加新的character
参数来更新状态。
# src/App.js
handleSubmit = character => {
this.setState({ characters: [...this.state.characters, character] })
}
确保我们将其作为Form
上的参数传递。
<Form handleSubmit={this.handleSubmit} />
现在,在Form
中,我们将创建一个称为SubmitForm()
的方法,该方法将调用该函数,并将Form
状态作为我们先前定义的character
参数传递。还将状态重置为初始化状态,以便在提交后清除表单。
# src/Form.js
submitForm = () => {
this.props.handleSubmit(this.state)
this.setState(this.initialState)
}
最后,我们将添加一个提交按钮以提交表单。因为我们没有使用标准的提交功能,我们我们使用的是onClick
而不是onSubmit
。点击将调用我们刚才创建的submitForm
。
<input type="button" value="Submit" onClick={this.submitForm} />
就是这样!该应用程序已经完成了。我们可以在表中创建,添加和删除用户。由于Table
和TableBody
已经从状态中拉出,因此将正确显示。
如果你有疑问,你可以在我的github上查看源码。
拉取API数据
React
的一种非常常见的用法是从API
提取数据。如果你不熟悉什么是API
或者如何连接API
,我建议你阅读下如何使用JavaScript连接API这篇文章,它将引导你了解什么是API
以及如何将它们与原始的JavaScript
一起使用。
作为一个小测试,我们可以创建一个新的Api.js
文件,并在其中创建新的App
。我们可以测试的公共API
是Wikipedia API,我这里有一个URL断点,可以进行随机*
搜索。你可以点击刚才的连接进入查看API
- 当然,确保你的浏览器上安装了JSONView。
我们将使用JavaScript的内置Fetch从该URL
断点中收集数据并展示它。你只需要更改index.js
中的URL
-import App from './Api';
,即可在我们创建的应用程序与该测试文件之间切换。
我不会逐行解释此代码,因为我们已经学习了有关通过状态数组来创建组件,渲染和映射的知识。此代码的新方面是componentDidMount()
,这是一种React
生命周期方法。生命周期是在React
中调用方法的顺序。挂载mounting是指项目已经插入DOM
中。
当我们提取API
数据时,我们要使用componentDidMount
,因为我们要确保在导入数据之前已经将组件渲染到DOM
。在以下代码段中,你将看到我们如何从Wikipedia API
引入数据,并将其显示在页面上。
# Api.js
import React, { Component } from 'react'
class App extends Component {
state = {
data: [],
}
// Code is invoked after the component is mounted/inserted into the DOM tree.
componentDidMount() {
const url =
'https://en.wikipedia.org/w/api.php?action=opensearch&search=Seona+Dancing&format=json&origin=*'
fetch(url)
.then(result => result.json())
.then(result => {
this.setState({
data: result,
})
})
}
render() {
const { data } = this.state
const result = data.map((entry, index) => {
return <li key={index}>{entry}</li>
})
return <ul>{result}</ul>
}
}
export default App
一旦你在本地服务器中保存并运行此文件后,你将看到DOM
中显示的Wikipedia API
数据。
还有其他生命周期的方法,但是这里将不再讨论它们。你可以在此处于阅读有关React组件的更多信息。
*维基百科搜索选项可能不是随机的。 这可能是我在2005年率先发表的文章。
构建和发布一个React应用
到目前为止,我们所做的一切都在开发环境中。我们一直在进行即时的编译,热重载和更新。对于生产环境,我们将要加载静态文件 - 没有源代码。我们可以通过构建并部署它来做到这一点。
现在,如果你只想编译所有React
代码并将其放置在某个目录的根目录中,则只需运行以下代码:
npm run build
这将build
一个包含你的应用程序的构建文件夹。将文件夹放在你想要的位置就可以了。
我们可以更进一步,让npm
为我们部署。我们将构建Github pages
,因此你必须熟悉Git并在Github
上获取代码。
确保你已经退出本地React
环境,因此该代码未在当前运行。首先,我们要在package.json
中添加一个homepage
字段,其中包含我们希望应用程序继续存在的URL
。
# package.json
"homepage": "https://taniarascia.github.io/react-tutorial",
我们也需要将下面的两行代码添加到scripts
的属性中。
# package.json
"scripts": {
// ...
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
}
在你的项目中,将gh-pages
添加到devDependencies
npm install --save-dev gh-pages
我们将创建build
,其中将包含所有已编译的静态文件。
npm run build
最后,我们将部署到gh-pages
。
npm run deploy
完成部署后,你可以通过https://taniarascia.github.io/react-tutorial 查看。
总结
本文很好地向你介绍了React
,简单组件和类组件,状态,属性,使用表单数据,从API
提取数据以及部署应用程序。使用React
还有更多的东西要学习和实践,但是我希望你现在有足够的信心钻研React
并学下去。
- View Source on GitHub
- View Project