【译】开始学React — 一个概括性的演练教程

757 阅读24分钟

我一开始学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可以使用stateprops特性来简化数据的存储和处理流程。

我们会在这篇文章中讲解这些甚至是更多,所以让我们开始。

开始和安装


有很多方法可以开始使用React,这里我只展示两种方法,以便你可以搞清楚如何启动一个react。

静态HTML文件

第一个启动React的方法不是很流行,和我们之后教程里的做法也不相同,但是如果你熟悉像Jquery这样的库,这个方法会更熟悉更容易理解。如果你不熟悉Webpack,Babel和Nodejs,那这个方法是代价最小的方法了

我们先创建一个基本的index.html文件,然后我们在head头部加入这三个CDN——React,React DOM和Babel。同时创建一个id为rootdiv标签,最后我们创建script标签来放我们要写的React代码

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>

我加载的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/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>

现在,如果你在浏览器看你的渲染结果,你可以看到h1标签已经被渲染出来了

来自https://www.taniarascia.com

太酷了!想必你做到这里,可以看出开始使用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应用。

来自https://www.taniarascia.com

如果你去看项目结构,你会看到/public/src目录,以及我们常看到的node_modules.gitgnoreREADME.mdpackage.json

/public目录下,最重要的文件就是index.html,这个我们之前创建的静态index.html是类似的,只有一个rootdiv。但是这次,没有任何库文件或者是script标签被引入。/src目录下将包含所有我们需要的React代码。

想要看环境是如何自动化编译和更新你的React代码的,你可以去在/src/App.js中找下面这行。

To get started, edit `src/App.js` and save to reload.

然后用其他任何文本替换它。一旦你保存文件,你会发现localhost:3000编译并用新数据刷新了页面

继续,我们删除/src目录下的所有文件,我们将创建我们自己的模板文件。我们将仅保留index.cssindex.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输出。目前你似乎看不出来这有什么大不了的,但是当这个应用编译的内容越来越多的时候,这个插件就显得极为必要。

来自https://www.taniarascia.com

现在我们准备好了所有的工具和配置,我们需要真的开始学习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 componentsimple 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'

然后在Apprender()函数中加载它,就是之前我们写"Hello,React!"的地方。我也把外面的div的类名改为container

return (
  <div className="container">
    <Table />
  </div>
)

回去查看浏览器,你可以看到Table加载出来了

来自https://www.taniarascia.com

现在你看到了什么是一个自定义的类组件。我们可以无数次地复用这个组件。然而,因为数据是硬编码进去的,这个组件现在可用性较差。

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的方法。

来自https://www.taniarascia.com

这里的数据还不是真实的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了

来自https://www.taniarascia.com

我这里删除了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的变化

来自https://www.taniarascia.com

很酷吧!最后一步就是要真的可以提交数据并更新父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} />

完成了!我们可以从列表中创建,添加和删除用户。只要TableTableBody已经从state拉取到数据,那么他就可以正确的展示出来。

来自https://www.taniarascia.com

如果你在那个地方不明白了,你可以看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的数据展示到了页面上

来自https://www.taniarascia.com

当然还有其他的一些生命周期函数,但是讲解那些超出了本篇文章的范围。你可以参阅 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-pagesdevDependencies

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…