关于本译文,我的小说明:
最近在学习React,看到这篇特别详细的入门文章,觉得很棒,就想赶在青年节结束之前,翻译并分享出来。这是本人第一篇技术译文,即便花费了好几天时间,也还是可能存在一些翻译不到位的地方。如果可爱的你发现了什么错误,别被我误导,以原文的意思为准~😸😸😸
以下为正文:
当我第一次开始学JavaScript时,就已经听说过React了。
但我得承认,当我看了一眼React后,我就被吓到了:我看到一堆与JavaScript混合在一块儿的HTML,心想,这种形式不是我们应该避免的吗?React有啥了不起的地方?
作为代替,我只专注于学习原生JS,并在专业的环境下使用jQuery。经过一些迷茫、失败的尝试之后,我最终开始明白,为什么我或许更想使用React而非原生JS或jQuery。
前提条件
以下是一些你在开始玩转React之前需要提前了解的东西。举个例子,如果你之前从来都没有使用过JavaScript或者DOM,那么在尝试使用React之前,最好先熟悉了解这些基础知识。
• 熟悉HTML&CSS
• 了解JavaScript
及其语法
• 理解DOM
• 熟悉Es6
语法及其特性
• 全局安装了Node.js
和npm
目标
- 了解React基本的概念及术语。比如Babel、Webpack、JSX、组件、props、state以及生命周期
- 创建一个能演示上述概念的简单Reac应用程序
以下是最终需要完成的Reac应用程序的资源和在线demo地址:
什么是React?
- React是一个受欢迎的JavaScript库,在Github上拥有超过100,000个的star
- React不是一个框架(与Angular不同,React更偏向自用)
- React是一个由Facebook创建的开源项目
- React是MVC应用程序((Model、View、Controller))中的view层
React最重要的一个方面就是你可以创建自定义、可重复利用的组件,并用来快速高效的构建用户界面。React也通过使用state
和props
精简了数据被存储和处理的过程。
引入React
有好几种引入React的方式,我会向你展示其中的两种,以便你能更好地了解它的运作方式。
静态HTML文件
第一种引入React的方法并不常用,也不是我们将在本文中重点实践的。但如果你曾经使用过jQuery之类的库,那么这种方式就会很容易理解。而且,如果你不熟悉Webpack,Babel和Node.js,这是最不可怕的入门方法。
让我们从创建一个基础的index.html
文件开始。
在head
中通过引入CDN的方式,引入React、React DOM以及 Babel.
然后创建一个div
,为之添加一个名为root的id;最后,再创建一个script
标签,用来编辑你的自定义代码。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Hello React!</title>
<script src="https://unpkg.com/react@^16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16.13.0/umd/react-dom.production.min.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>
我在写这篇文章时,以下依赖我使用的是最新的稳定版本:
我们的应用程序的入口点是之前创建的div元素,该元素按照惯例命名。你也会注意到script的类型是text/babel
,这是在使用Babel时必须添加的。
现在,我们来编写React的第一个代码块。我们将使用ES6中的类来创建一个React组件,称作App
。
class App extends React.Component {
//...
}
接下来添加render()
方法,这是唯一一个在类组件中需要使用的方法,用于渲染DOM节点。
class App extends React.Component {
render() {
return (
//...
);
}
}
在return
中,我们将放入一段看起来像简单HTML节点的代码块。
注意,在这里并不是要返回一个字符串,所以不要在元素周围使用引号。
这种语法称作JSX
,我们很快会学到更多相关的东西。
class App extends React.Component {
render() {
return <h1>Hello world!</h1>
}
}
最后,我们使用React DOM的render()
方法将我们创建的App
类渲染至HTML的节点div
中。
ReactDOM.render(<App />, document.getElementById('root'))
以下是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
,你会看见我们创建的h1
标签已经被渲染到了DOM中。
棒棒哒! 现在你已经完成了这一步,你会发现入门React并没有那么的吓人。它只是一些我们能将其加载到HTML中的JavaScript辅助库。
用这种方式我们已经完成了演示应用程序的目标,但除此之外,我们还可以使用另一种引入react的方法: Create React App.
Create React App
上述使用的方法是将JavaScript库加载至静态HTML文件中,并实时渲染React和Babel。这种方式并不高效,而且代码也很难维护。
幸运的是,Facebook支持通过Create React App这种方式来构建React App,这种方式预先配置了构建React应用所需的所有依赖项。
Create React App
会创建一个实时的开发服务器,使用Webpack来自动编译React、JSX、ES6以及自动给CSS文件增加前缀。此外,它还会使用ESLint测试代码并告警代码中的错误。
在终端运行以下代码以安装create-react-app
,项目所在目录由你自己决定
npx create-react-app react-tutorial
安装成功后,进入刚才新建的项目目录里,并运行项目
cd react-tutorial
npm start
当你执行上述命令后,你新创建的React app将会运行在新浏览器窗口localhost:3000
Create React App 很适合初学者以及大型企业应用使用,但并不适合所有情况。你也可以为React创建自己的Webpack设置。
如果你查看项目的结构,你会看到/public
和/src
文件夹,还有常见的node_modules, .gitignore, README.md
以及 package.json
。
在/public
目录中,最重要的文件是index.html
,它与我们前面创建过的静态HTML文件index.html
很相似—只有一个根
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
,我为了操作起来简单,只是将原生的CSS粘贴复制到文件里了,如果你需要的话,你可以使用BootStrap或者其他任何你需要的CSS框架,或者啥都不用。
在index.js
中,引入React、ReactDOM以及index.css
。
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
让我们再次来创建App
组件吧。之前的例子里,只有一个h1
标签,但现在我还添加了一个带有类的div。你会发现代码中使用的是className
而非class
。这是第一个暗示:我们此处编写的代码是JavaScript,而不是HTML。
class App extends Component {
render() {
return (
<div className="App">
<h1>Hello, React!</h1>
</div>
)
}
}
最后,和之前一样,将App
渲染至根节点中。
ReactDOM.render(<App />, document.getElementById('root'))
下面是index.js
中的完整代码,这次,我们将Component
作为React的一个属性加载,因此extends
后面不再需要写成 React.Component
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 Developer Tools
React Developer Tools是一个扩展工具,它能帮助你更轻松的调试React。下载Chrome下的React Developer Tools,或者在其他你更喜欢的浏览器下载。
安装完之后,打开谷歌开发者工具(DevTools),你会看见一个React
的标签页。点击这个选项卡,你就能够在编写组件时在DevTools中检查它们。
你也可以在Elements
的选项卡中,查看真实的DOM输出。现在看起来这个工具并没有起多大作用,但是当你的React应用程序变得越来越复杂时,使用该工具就会变得愈加重要。
截止现在,我们已经有了所有开始使用React的配置和工具。
JSX: JavaScript + XML
正如你看到的那样,我们在React代码中使用了看起来像HTML的代码,但它其实并不是HTML。这种语法称为JSX
,指的是JavaScript XML。
我们可以使用JSX编写类似于HTML的内容,也可以自定义类XML标签。
下面是JSX赋值给一个变量的例子:
const heading = <h1 className="site-heading">Hello, React</h1>
React并不强制你使用JSX,每个 JSX 元素只是调用 React.createElement(component, props, …children) 的语法糖。
下面的代码会和JSX有相同的输出结果:
const heading = React.createElement('h1', { className: 'site-heading' }, 'Hello, React!')
JSX更接近于JS,而非HTML。因此在编写JSX时有一些关键的不同点需要注意:
- 增加css类时,应该使用
className
而非class
,因为class
在JS中是一个保留关键字。 - JSX中的属性和方法的命名遵循小驼峰法。(onclick应该变为onClick)
- 自闭合的标签必须以
/
结尾.例如,<img />
JavaScript表达式也可以使用大括号(包括变量,函数和属性)嵌入JSX内。
const name = 'Tania'
const heading = <h1>Hello, {name}</h1>
JSX比原生JS更容易编写和理解,这也是React如此受人们喜欢的原因之一。
组件
截止现在,我们已经创建了一个名为App
的组件,React中几乎所有东西都由组件构成,组件可以是类组件或者简单组件。
大多数React应用程序都有很多小组件,所有小组件都会被加载到主要的App
组件中。组件通常也会有自己的文件,所以让我们来改变项目的结构:
在index.js
中移除App
类,代码会变成这样:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import './index.css'
ReactDOM.render(<App />, document.getElementById('root'))
接下来,创建一个叫做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组件。新建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组件了,第一步,引入它:
import Table from './Table'
然后将其加载到App
的render()
中,位置是之前我们放置"Hello,React"的地方。我也更改了div容器的类名。
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组件中编写两个简单的组件:一个表头( table header)、一个表体(table body)
我们将使用ES6的箭头函数来创建这两个组件。首先,创建表头组件:
const TableHeader = () => {
return (
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
)
}
然后创建表体组件:
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文件看起来应该是这样:
const TableHeader = () => { ... }
const TableBody = () => { ... }
class Table extends Component {
render() {
return (
<table>
<TableHeader />
<TableBody />
</table>
)
}
}
注意,TableHeader
以及TableBody
组件都在同一个文件中,并且会被类组件Table
使用。
如你所见,组件可以被嵌套在其它组件中,而且简单组件、类组件可以混合使用。
类组件必须包含
render()
,且只能返回一个父元素。
最后,我们来简单比较一下函数组件和类组件:
函数组件:
const SimpleComponent = () => {
return <div>Example</div>
}
类组件:
class ClassComponent extends Component {
render() {
return <div>Example</div>
}
}
注意,如果return
的内容只有一行,则不需要使用括号。
Props
现在我们已经有了一个很棒的Table
组件,但是数据被硬编码了。学习React时,一个很重要的问题就是了解它是如何处理数据的。React通过属性(称为props)以及状态来处理数据。
现在,我们先来关注如何使用props来处理数据:
首先,将TableBody
组件中先前的数据全部删掉,只保留下面的部分:
const TableBody = () => {
return <tbody />
}
然后将刚才被移除的数据移动到一个对象数组中,这与引入一个基于JSON的API类似。这个对象数组需要在render
里面创建。
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,由于characters是变量,所以需要用大括号括起来。
return (
<div className="container">
<Table characterData={characters} />
</div>
)
现在数据已经被传递进Table
组件中了,我们必须在另一端(Table组件中)进行访问。
class Table extends Component {
render() {
const { characterData } = this.props
return (
<table>
<TableHeader />
<TableBody characterData={characterData} />
</table>
)
}
}
打开React DevTools并检查Table
组件,你会在属性中看到含有数据的数组。被存储在这里的数据称为虚拟DOM—一种可以快速高效的将数据与真实DOM同步的方法。
但是,这里的数据尚未存储在真实DOM中,在Table
组件中,我们可以通过this.props
访问所有的props
属性。在这里,我们只需要传递一个名为characterData的prop,通过this.props.characterData
来获取数据。
我将使用ES6语法来创建一个包含this.props.characterData
的变量:
const { characterData } = this.props
既然Table
组件是有两个简单组件组成的,我将再一次通过传递props来将数据传入TableBody
组件里。
class Table extends Component {
render() {
const { characterData } = this.props
return (
<table>
<TableHeader />
<TableBody characterData={characterData} />
</table>
)
}
}
TableBody
组件目前没有携带任何参数,并返回单个标签。
const TableBody = () => {
return <tbody />
}
现在,将props作为TableBody组件的参数,遍历characterData数组,并将数组中的每项值作为表格的行数据返回。
遍历结果将包含在rows
变量中,并以表达式的形式返回。
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里创建列表时,都需要使用键,因为它们有助于识别每个列表项。 在你需要操作列表的每一项时,就会知道这么做的原因。
props是一种高效的向React组件传递数据的方式,但组件不能修改props,因为props是只读的。在下面的内容中,我们将会了解到,在React中如何使用状态(state
)来更进一步的控制数据的。
状态(state)
我们已经将characterData
以数组形式存储在一个变量中,并且通过props传递它。这是一个好的开端,但如果我们想删除数组中的某一项,使用props,会受到单向数据流的限制。然而,使用state,我们就能够更新组件中的私有数据。
你可以将state
视为任何需要进行保存或修改的数据,这些数据不需要被添加到数据库中。这与你在确认购买东西之前,在购物车中添加和删除商品的操作类似。
让我们创建一个state
对象:
class App extends Component {
state = {}
}
这个对象可以包含所有你想存储到state中的数据。对我们来说,需要存储的数据是characters
。
class App extends Component {
state = {
characters: [],
}
}
将我们先前创建的整个对象数组移到state.characters中。
class App extends Component {
state = {
characters: [
{
name: 'Charlie',
// the rest of the data
},
],
}
}
我们所需要的数据已经正式包含在了state中,既然我们想要从表格中删除一项数据,我们可以在App
组件中创建一个removeCharacter
方法。
为了获取state,我们将和先前一样,使用ES6语法来获取this.state.characters
。
我们可以使用this.setState()
(React处理状态的内置方法)来更新state,我们将根据索引值过滤数组,并返回新数组。
你必须使用
this.setState()
修改数组。仅将新值应用于this.state.property
并不会起作用。
//App.js
removeCharacter = index => {
const { characters } = this.state
this.setState({
characters: characters.filter((character, i) => {
return i !== index
}),
})
}
filter
方法不会改变原数组,它返回过滤后的新数组。它是一个在JS中修改数组的好方法。(filter 为数组中的每个元素调用一次回调函数函数,并返回一个由通过测试的元素组成的数组)
接下来,需要将removeCharacter
函数传递给组件,并在每个可以调用该函数的字符旁边绘制一个按钮。我们将通过prop的方式传递removeCharacter
函数。
//App.js
render() {
const { characters } = this.state
return (
<div className="container">
<Table characterData={characters} removeCharacter={this.removeCharacter} />
</div>
)
}
现在,我们已经将removeCharacter
从Table
组件传递到了TableBody
中,我们需要再次使用props的方式来传递removeCharacter
,与传递characterData
类似。
此外,在我们的项目中,拥有自身状态的组件为App
和Form
组件,将Table
组件由当前的类组件转换为函数组件,会是一次不错的实战。
//Table.js
const Table = props => {
const { characterData, removeCharacter } = props
return (
<table>
<TableHeader />
<TableBody characterData={characterData} removeCharacter={removeCharacter} />
</table>
)
}
下面就是我们在removeCharacter()
方法中定义的索引的输入位置。在TableBody
组件中,我们将把键/索引作为参数传递,因此过滤器函数需要知道哪一项需要被删除。 我们将创建一个带有onClick
函数的按钮并将其传递:
<tr key={index}>
<td>{row.name}</td>
<td>{row.job}</td>
<td>
<button onClick={() => props.removeCharacter(index)}>Delete</button>
</td>
</tr
OnClick函数必须通过一个返回
removeCharacter
方法的函数传递,否则OnClick将会尝试自动执行。
现在我们已经有了删除按钮,而且能够通过删除一个字符来修改state
我删除了表格中名为Mac的那行数据。
现在你应该已经能理解状态是如何初始化的,以及是如何被修改的。
提交表单数据
现在,已经有数据被存储在了state中,我们也能够从state中移除数据中的任何一项。但是,如果我们想给state中增加一项数据呢?在一个真实的应用程序中,你更可能会从一个空state中入手,并往里添加数据,比如说开发一个to-do-list清单或者一个购物车功能。
首先,让我们从state.characters
中删除所有硬编码的数据,因为我们现在将通过表单进行数据的更新。
//App.js
class App extends Component {
state = {
characters: [],
}
}
接下来,创建一个新文件Form.js
名,并在其中创建一个名为Form
的组件。
将Form的初始状态设置为具有一些空属性的对象,并将该初始状态分配给this.state
。
//Form.js
import React, { Component } from 'react'
class Form extends Component {
initialState = {
name: '',
job: '',
}
state = this.initialState
}
React早前的版本需要在类组件上包含
constructor()
,但现在不再需要了。
关于该表单,我们的目标是: 每次在表单中更改字段时都会更新Form的状态,并且在提交时,所有这些数据都将传递到App
组件的state中,然后App的state将会更新表格中的数据。
首先,我们将创建一个每次对输入进行更改时都将运行的函数。 该事件被执行后,设置Form的状态为输入的名称(键)和值。
//Form.js
handleChange = event => {
const { name, value } = event.target
this.setState({
[name]: value,
})
}
在提交表单之前,我们先让这个函数可以运行。
首先,在render()
里,从state中获取两个属性,并将它们分配为表单的键所对应的值。 然后运行handleChange(
方法,最后,导出Form组件。
//Form.js
render() {
const { name, job } = this.state;
return (
<form>
<label htmlFor="name">Name</label>
<input
type="text"
name="name"
id="name"
value={name}
onChange={this.handleChange} />
<label htmlFor="job">Job</label>
<input
type="text"
name="job"
id="job"
value={job}
onChange={this.handleChange} />
</form>
);
}
export default Form;
在App.js
中,我们可以在table下面渲染Form表单。
//App.js
import Form from './Form';
//App.js
return (
<div className="container">
<Table characterData={characters} removeCharacter={this.removeCharacter} />
<Form />
</div>
)
现在,如果我们转到应用程序的前端界面,将会看到尚未提交的表单。 更新一些字段,你将看到正在更新的Form的本地状态。
很棒! 最后一步是使我们能够真正提交该数据并更新父级的状态。 我们将在App上创建一个名为handleSubmit()
的函数,该函数将通过使用ES6扩展运算符获取现有的this.state.characters
,并添加新的character
参数来更新状态。
//App.js
handleSubmit = character => {
this.setState({ characters: [...this.state.characters, character] })
}
请确保将handleSubmit()
函数作为Form
组件的一个参数进行传递。
<Form handleSubmit={this.handleSubmit} />
现在在Form中,我们将创建一个名为SubmitForm()
的方法,该方法将调用该函数,并将Form
的state作为我们先前定义的character
参数传递。 同时,在SubmitForm()
方法中,将state重置为初始状态,以便在提交后清除表单。
//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
已经从state中取出了,因此能够正确的在table中显示。
上述步骤中,如果你有任何疑惑的地方,可以在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,即可在我们创建的应用程序与该测试文件之间进行切换。
我不会逐行解释下述代码,因为我们已经学习了关于通过一个状态数组,来创建组件,渲染组件以及遍历组件的知识。下述代码新引入的概念是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还有其他的生命周期方法,但是本文不再具体讨论它们。你可以在这里了解更多有关生命周期的知识。
构建并部署React应用
到目前为止,我们所编写的一切代码都在开发环境中。 我们一直在进行即时的编译,热重载和更新。 在生产环境中,我们将会加载静态文件-没有源代码。 我们可以通过构建并部署它来做到这一点。
现在,如果你只想编译所有React代码并将其放置在某个目录的根目录中,则只需运行以下代码:
npm run build
这个命令将构建一个包含应用程序的构建文件夹。 将文件夹的内容放在任何地方,你就可以完成部署了!
我们还可以更进一步: 部署npm。 这一步我们将会构建至GitHub页面,因此你必须熟悉Git,并在GitHub上获取代码。
如果已经确保你已经退出了本地的React开发环境,那么代码当前并没有运行。 首先,在package.json
中添加一个homepage
字段,其中包含我们希望应用程序所在的URL。
"homepage": "https://taniarascia.github.io/react-tutorial",
再将下面这两行代码添加到scripts属性上:
"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
现在我们已经完成了部署,你已经可以在taniarascia.github.io上查看这个应用程序啦~
结论
本文应该已经很好地向你介绍了React的简单/类组件、状态、props、在React中如何使用表单数据、从API提取数据以及部署应用程序。
使用React还有更多的东西要学习和实践,但是我希望你现在已经有信心钻研和玩转React了!
原文地址: https://www.taniarascia.com/getting-started-with-react/