我一开始学Javascript的时候就听说过React了,但是我得承认当我看了一眼React后,它吓到我了。我看到了一堆HTML混合着Javascript,然后我想,这不是我们努力避免的事情吗?React到底有什么大不了的?
没有过多关注React,相反,我只是关注于学习VanilaJS(额,其实就是纯粹的原生JS,VanillaJs=Javascript)并在工作环境里使用Jquery。我几次想试图开始使用React,但是都失败了,最终我决定好好学习React,我开始去了解为什么我可能想要使用Reacte而不是原生的JS或是Jquery?
我尽力把所有我学过的东西压缩成了这一篇很好的导学教程,分享给大家,让我们开始。
先决条件
在开始玩React之前,有一些你必须提前知道的知识。如果你从来没有使用过Javascript或者是一点都不了解DOM,我建议在尝试学习React之前先熟悉这些内容。
以下是我认为的学习React的先决条件:
- 基本熟悉HTML 和 CSS
- 基本掌握 Javascript编程
- 基本理解 DOM
- 熟悉ES6的语法与特性
- Nodejs 和 npm 全局安装
目标
- 学习React重要的概念和相关的技术,比如,Babel,Webpack,JSX,components,props,state 和 lifecycle
- 构建一个简单的react-app来演示上面的那些概念
下面是源代码和最终结果的真实demo
什么是React?
- React是一个Github上最流行的JS库之一,有超过100000个Star
- React并不是一个框架(不像Angular)
- React是一个由Facebook创建的开源项目
- React用来构建前端UI
- React是MVC应用的View层
在React中最重要的一个方面就是你可以像创建HTML元素一样创建自定义可重用的组件,来快速高效的构建UI。同时,React可以使用state和props特性来简化数据的存储和处理流程。
我们会在这篇文章中讲解这些甚至是更多,所以让我们开始。
开始和安装
有很多方法可以开始使用React,这里我只展示两种方法,以便你可以搞清楚如何启动一个react。
静态HTML文件
第一个启动React的方法不是很流行,和我们之后教程里的做法也不相同,但是如果你熟悉像Jquery这样的库,这个方法会更熟悉更容易理解。如果你不熟悉Webpack,Babel和Nodejs,那这个方法是代价最小的方法了
我们先创建一个基本的index.html
文件,然后我们在head
头部加入这三个CDN——React,React DOM和Babel。同时创建一个id为root
的div
标签,最后我们创建script
标签来放我们要写的React代码
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Hello React!</title>
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/[email protected]/babel.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
// React code will go here
</script>
</body>
</html>
复制代码
我加载的CDN是写这篇文章时最新的稳定版本
- React —— React顶层API
- React DOM —— 添加DOM专用的方法
- Babel —— 一个可以让我们在浏览器使用ES6+的JS编译器
我们应用的入口就是那个id为root
的div元素,命名为root
只是一种习惯上的命名,你完全可以命名为其他的。你可能注意到了script
标签中的类型是text/babel
,这是强制使用babel的意思。
现在,我们来写我们的第一段React代码片。我们将用ES6的类来创建一个叫App的React组件。
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()
方法把我们在root
节点上创建的App
类组件渲染出来。
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/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/[email protected]/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>
复制代码
现在,如果你在浏览器看你的渲染结果,你可以看到h1
标签已经被渲染出来了
太酷了!想必你做到这里,可以看出开始使用React并不是像想象中的那样令人畏惧。他只不过是一些我们可以加载到HTML中的JavaScript帮助库罢了。
以上我们做的都是为了演示目的,但是从这里开始我们将使用另一种方法:Create React App。
Create React App
在静态文件里加载Javascript库,渲染React并实时Babel编译的方法是很不高效且难以维护。
幸运的是,Facebook创造了Create React App ,一个预先配置好了所有在构建React应用时所需的的环境。它会创建一个实时的开发服务器,使用webpack自动编译React、JSX和ES6,自动添加CSS文件前缀,并且使用ESlint测试和警告代码中的错误。
要启动Create-react-app,你需要在你的终端运行以下代码,一个新的目录会被创建到当前目录下。请确保你有5.2或者更高版本的Nodejs环境。
npx create-react-app react-tutorial
复制代码
一旦完成安装,移动到新建的目录里并启动项目。
cd react-tutorial
npm start
复制代码
执行完上面的命令,浏览器会弹出新窗口,并用localhost:3000
服务你的新建的React应用。
如果你去看项目结构,你会看到/public
和/src
目录,以及我们常看到的node_modules
、.gitgnore
、README.md
和package.json
。
在/public
目录下,最重要的文件就是index.html
,这个我们之前创建的静态index.html
是类似的,只有一个root
div。但是这次,没有任何库文件或者是script
标签被引入。/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>
,但是现在我们把它添加进一个带有class
属性的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的一个属性加载,所以我们不用在继承自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 Developer Tools
有一个插件叫React Developer Tools , 可以让你更简单的玩React。下载React DevTools for Chrome,或者其他任何你喜欢的浏览器对应的插件。
安装完后,当你打开DevTools时,你会看到一个React专门的标签栏。点击他,你就可以检查你之前写的组件,但这并不妨碍你去Element
标签栏看真实的DOM输出。目前你似乎看不出来这有什么大不了的,但是当这个应用编译的内容越来越多的时候,这个插件就显得极为必要。
现在我们准备好了所有的工具和配置,我们需要真的开始学习React了。
JSX:JavaScript + XML
如你所见,我们正在使用看起来像HTML的代码构建React组件,但是他不是真正的HTML。那是JSX,是JavaScript XML的缩写。
使用JSX,我们可以像HTML那样书写,也可以创建和使用我们自己的类XML标签。下面是将JSX赋给一个变量。
JSX
const heading = <h1 className="site-heading">Hello, React</h1>
复制代码
写React并不强制使用JSX。深入原理,React执行的其实是createElement
,通过这个方法传入标签、包含属性的对象,以及子组件这些参数,并渲染,可以得到相同的结果。下面的代码的输出等同于上面JSX。
Non-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>
复制代码
比起用原生JS创建和添加许多元素,JSX更容易书写,并且好理解,这也是人们钟爱React的一个原因。
Components
目前为止,我们创建了一个组件——App
组件。在React中,几乎所有的东西都是由组件组成,组件分为两种,class component
和simple component
。
大部分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
的文件,然后把App
组件搬到这里
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
中加载它。这样把组件分隔到一个单独文件的做法不是强制的,但是如果你不这样做,应用将会变得笨重且难以控制。
Class Components
让我们再创建一个组件。我们将创建一个表格。新建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组件,首先像这样导入:
import Table from './Table'
复制代码
然后在App
的render()
函数中加载它,就是之前我们写"Hello,React!"的地方。我也把外面的div的类名改为container
return (
<div className="container">
<Table />
</div>
)
复制代码
回去查看浏览器,你可以看到Table
加载出来了
现在你看到了什么是一个自定义的类组件。我们可以无数次地复用这个组件。然而,因为数据是硬编码进去的,这个组件现在可用性较差。
Simple Components
另一种书写React组件的方法是simple component,它是一个函数。这个组件书写方式并不使用class
关键字。让我们把Table
组件分成两个simple component——一个表头,一个表体
我们将使用ES6的箭头函数来创建这些simple component。首先是表头,
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
类看起来是这样的
class Table extends Component {
render() {
return (
<table>
<TableHeader />
<TableBody />
</table>
)
}
}
复制代码
一切都可以像之前那样显示出来,你可以在浏览器中看到和之前一样的表格。如你所见,组件可以嵌入另一个组件,且simple component 和 class component可以混合使用。
一个类组件必须包含
render()
,且return
只能返回一个父元素(也即根节点只能有一个)
做个总结,我们来对比一下simple component和class component。
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
里的所有数据
Table.js
const TableBody = () => {
return <tbody />
}
复制代码
然后我们把数据移入到一个数组对象中去,就好像我们引入了一个基于JSON的API。我们必须在我们的render()
中创建这个数组
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-attributes
的方式传递数据。我们可以给这个属性起任何名字,只要它不是预留的关键字即可,因此我给他命名为characterData
。我要传递的数据是characters
变量,且我会用大括号包含它,因它属于JS表达式。
return (
<div className="container">
<Table characterData={characters} />
</div>
)
复制代码
现在数据正传递给Table
,我们必须在另一边接受它。
Table.js
class Table extends Component {
render() {
const { characterData } = this.props
return (
<table>
<TableHeader />
<TableBody characterData={characterData} />
</table>
)
}
}
复制代码
如果你打开React DevTools并检查Table
组件,你会发现在属性中出现了这个数组。存储这里的数据就是广为人知的VirtualDOM,一个更快更高效的同步数据与实际DOM的方法。
这里的数据还不是真实的DOM。在Table
中,我们可以通过this.props
接受所有的props。我们这里只传递了一个props——characterData,所以我们使用this.props.characterData
来取回数据
const { characterData } = this.props
复制代码
因为Table
组件实际上由两个小的simple component组成,所以我们再次通过props将数据传递给TableBody
。
Table.js
class Table extends Component {
render() {
const { characterData } = this.props
return (
<table>
<TableHeader />
<TableBody characterData={characterData} />
</table>
)
}
}
复制代码
到这里,TableBody
函数没有任何参数,且仅是返回一个标签。
const TableBody = () => {
return <tbody />
}
复制代码
我们将传递props作为函数参数,并通过Array.map方法来为数组中每一个对象返回一个表项。这个映射后的数组赋给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>
}
复制代码
如果你去看应用的页面,所有的数据都已经加载出来了。
你可能注意到我为每一个表项加入了一个key(index)。当你在React中构建列表时,你应该总是使用key,因为这些key可以帮助标识每一个表项。等会当我们想要操纵表项时,我们就知道他的必要性了。
Props是一种高效的方式传递已存在的数据给React组件,但是组件并不能改变props——他们是只读的。在下一章节中,我们将学习如何使用state来实现在数据处理中更多的控制力。
State
目前为止,我们将character数据存入一个数组变量,并通过props传递它。这是一个好的开始,但是想象一下如果我们需要从数组中删除一项,使用props,我们只有单向数据流,但是使用state我们可以从组件中更新私有数据。
我们可以把state看作是那些需要保存和修改但是不需要添加至数据库的任何数据。举个例子,再确认购买之前从购物车中添加或删除一项,就是state的场景。
一开始,我们先来创建一个state对象
class App extends Component {
state = {}
}
复制代码
这个对象将包含所有你想存储在state中的属性。对我们而言,这个属性是character
。
class App extends Component {
state = {
characters: [],
}
}
复制代码
把我们之前创建的完整数组对象移到state.characters
中去
class App extends Component {
state = {
characters: [
{
name: 'Charlie',
// the rest of the data
},
],
}
}
复制代码
我们的数据现在正式包含在了state中。由于我们想要从表格中删除一个项character,我们现在将要在App
类内创建一个removeCharacter
方法。
为了取得state,我们使用和之前一样的ES6语法this.state.characters
。为了更新state,我们将使用this.setState()
,这是一个为了控制state而内置的方法。我们将基于之前传递的index
来过滤数组,并返回过滤后的新数组。
你必须使用
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中修改数组的首选方式。这一方法用传入的index对比数组中所有下标,返回除了index对应的项以外的其他所有的项。
现在我们必须传递这个函数到组件中去,并且在每个表项旁渲染一个button以便触发此函数。我们将removeCharacter
作为一个prop传递给Table
。
App.js
return (
<div className="container">
<Table characterData={characters} removeCharacter={this.removeCharacter} />
</div>
)
复制代码
不要忘了写const { character } = this.state
来从state中获取正确的数据。
我们还要把它再次作为prop从Table
传递给TableBody
。
Table.js
class Table extends Component {
render() {
const { characterData, removeCharacter } = this.props
return (
<table>
<TableHeader />
<TableBody characterData={characterData} removeCharacter={removeCharacter} />
</table>
)
}
}
复制代码
下面就是我们在removeCharater()
定义的index的出处。在TableBody
组件里,我们把key/index作为参数传递,以致于过滤函数可以知道那一项需要被删除。我们将创建一个button并监听onClick
事件,并将index传递过去。
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
的函数,否则它就会尝试自动运行(而不是触发运行)
真棒!我们现在已经有了删除按钮,我们可以通过删除一项来修改我们的state了
我这里删除了Mac
现在你应该理解state是如何初始化和被修改的了吧
提交表单数据
现在数据存储在state中,我们可以从中随意删除任何一项。但是,要是我们想要添加新的数据到state中去呢?在真实的应用中,更可能的情况是一开始只是空的state,然后添加进东西,就像待办清单或是购物车一样。
在开始之前,我们删除掉state.characters
中所有硬编码的数据,因为我们现在需要通过表单来更新state
class App extends Component {
state = {
characters: [],
}
}
复制代码
创建一个Form.js
的新文件,并在文件里创建Form
组件。我们将创建一个类组件,并在类中使用constructor()
,这是我们至今还未提到过的。我们需要constructor()
来使用this
和接受父组件属性
我们将设置Form
的初始state为一个空的对象,然后将其赋给this.state
。
Form.js
import React, { Component } from 'react'
class Form extends Component {
constructor(props) {
super(props)
this.initialState = {
name: '',
job: '',
}
this.state = this.initialState
}
}
复制代码
这个表单的目标是每当表单中文本域发生改变时就更新Form
的state,然后,当我们提交时,所有数据都会传递给App
的state,这样就会引起Table
的更新
首先,我们创建一个函数,这个函数会在每次输入改变时执行。event对象将会被传递进去,我们可以由此来获取输入的name(key)
和value
,进而设置Form
的state
handleChange = event => {
const { name, value } = event.target
this.setState({
[name]: value,
})
}
复制代码
在我们能提交表单之前,我们先完成这个功能。在render函数里,可以从state中获取我们需要的两个属性,并把他们作为值赋给对应的表单。我们在input上监听onChange
,把handleChange()
作为监听函数。最后导出我们的Form
组件。
render() {
const { name, job } = this.state;
return (
<form>
<label>Name</label>
<input
type="text"
name="name"
value={name}
onChange={this.handleChange} />
<label>Job</label>
<input
type="text"
name="job"
value={job}
onChange={this.handleChange} />
</form>
);
}
export default Form;
复制代码
在App.js
里,我们可以在表格下面渲染这个表单
App.js
return (
<div className="container">
<Table characterData={characters} removeCharacter={this.removeCharacter} />
<Form />
</div>
)
复制代码
现在再去看看你的应用页面,你会看到一个还未提交的表单。更新文本域的内容,你会看到Form
本地state的变化
很酷吧!最后一步就是要真的可以提交数据并更新父state。我们将在App
类内创建一个handleSubmit()
函数,这个函数将使用扩展运算符(...)来把已存在的this.state.character
和新添加的character
参数铺平为一维数组进而更新state。
App.js
handleSubmit = character => {
this.setState({ characters: [...this.state.characters, character] })
}
复制代码
我们得确保这个函数传递给了Form
<Form handleSubmit={this.handleSubmit} />
复制代码
现在在Form
中,我们创建一个submitForm()
的函数,用来调用handleSubmit()
并将Form
的state作为handleSubmit()
的参数传递。再提交表单后,重置Form的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拉取到数据,那么他就可以正确的展示出来。
如果你在那个地方不明白了,你可以看GitHub上的完整源码
拉取API中的数据
React其中一个很常用的用法是从API中拉取数据。如果你尚不熟悉什么是API或者是如何连接一个API的话,我建议你读How to Connect to an API with JavaScript,这篇文章会带你浏览什么是API,以及如何在原生JS中使用他们
做一个小测试,我们可以创建一个API.js
文件,并在里面创建一个新App
组件。我们可以测试一个公共API——Wikipedia(需*,你可以自己写一个后端API服务做测试)。你可以点入链接去查看API——确保你的浏览器安装有JSONView。
我们将使用JS内置的Fetch
方法从URL端点获取数据并展示出来。通过改变index.js
中的导入文件——import App from './Api'
,你把之前的应用切换到测试文件。
我不打算再一行一行的解释代码了,因为我们已经学习了创建组件,渲染函数和state数组映射。这段代码新的部分就是componentDidMount()
,这是React的一个生命周期函数。生命周期就是React里方法调用的顺序。Mounting 指的是一个元素插入到DOM里的时候。
当我们从API中拉取数据时,我们希望使用componentDidMount
,因为我们希望确保在我们拿到数据之前组件就已经渲染到DOM上了。在下面的代码片中,你会看到我们是如何从Wikipedia API中获取数据并展示到页面上的。
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
复制代码
一旦保存并运行此文件,你就可以看到Wikipedia API的数据展示到了页面上
当然还有其他的一些生命周期函数,但是讲解那些超出了本篇文章的范围。你可以参阅 React Components 来了解更多
构建并部署一个React应用
目前为止,我们所作的一切都是在开发环境中进行的。我们实时地编译,热重载和更新。对于生产环境来说,我们更希望加载静态文件——而不是源代码。我们可以通过构建和部署做到这一点。
现在,如果你只是想编译所有React代码并把他放到根目录的某个地方的话,你只需要运行下面这样命令:
npm run build
复制代码
这个命令将会创建一个包含你的应用的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
复制代码
然后构建项目,我们就可以得到所有编译后静态的文件
npm run build
复制代码
最后,我们部署到gh-pages
npm run deploy
复制代码
全部完成了!这个应用现在可以运行在taniarascia.github.io/react-tutor…上了
总结
这篇文章应该在React入门(simple component 和 class component 、props 和 state 、处理表单数据、从API中获取数据、部署应用)方面给你了不错的指导。React还有很多需要学习的地方,但是我想你现在对自己独立钻研和玩React应该很有自信了吧。
本文译自Tania的个人博客,本篇博客已被官方网站收录为入门级教程,原文地址: www.taniarascia.com/getting-sta…