欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-11 14:58:53
...

我一开始学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/[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.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输出。目前你似乎看不出来这有什么大不了的,但是当这个应用编译的内容越来越多的时候,这个插件就显得极为必要。

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

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

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} />
复制代码

完成了!我们可以从列表中创建,添加和删除用户。只要TableTableBody已经从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-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…

转载于:https://juejin.im/post/5d0855965188254a6c23ed44