Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【译】开始学习React - 概览和演示教程 #59

Open
reng99 opened this issue Feb 18, 2020 · 0 comments
Open

【译】开始学习React - 概览和演示教程 #59

reng99 opened this issue Feb 18, 2020 · 0 comments
Labels
blog a single blog

Comments

@reng99
Copy link
Owner

reng99 commented Feb 18, 2020

当我刚开始学习JavaScript的时候,我就听说了React,但我承认看了它一眼,它吓到我了。我看到了看起来一堆HTMLCSS的混合思想,这不是我们一直努力避免的事情吗?React有什么了不起的?

相反,我只专注于学习原始的JavaScript,并在需要的时候使用jQuery。经过几次失败的React入门尝试之后,我终于开始了解它了,我开始明白为什么我可能想使用React而不是原始的JSjQuery

我试图将自己学到的内容浓缩成一个很好的介绍,以便与你分享,下面就是~

预备知识

在开始学习React之前,你应该事先了解一些事情。例如,如果你之前从没接触过JavaScript或者DOM,那么在解决React之前,你要更加熟悉它们。

下面是我认为学习React的预备知识:

目标

  • 了解基本的React概念和相关术语,例如BabelWebpackJSX,组件,属性,状态和生命周期
  • 通过构建一个非常简单的React应用程序,以演示上面的概念。

下面是最终的相关源代码和示例。

React是什么?

  • React是一个JavaScript库 - 最受欢迎的库之一,在GitHub上超过100,000星星
  • React不是一个框架(不像Angular,定位是框架)。
  • ReactFacebook的开源项目。
  • React用于在前端构建用户界面UI
  • ReactMVC (Model View Controller)应用的View层。

React的最重要的方面之一是可以创建类似于自定义、可复用的HTML元素的组件,以快速有效地构建用户界面。React还使用状态state属性props来简化数据的存储和处理方式。

我们将在本文中介绍这些内容及其更多的内容,我们来开始吧。

安装

有几种安装React的方法,我将向你展示两种,以便你更好地了解它地工作方式。

静态HTML文件

第一种方法不是安装React的流行方法,也不是我们本教程其余部分的工作方式,但是如果你接触过jQuery之类的库,这将很熟悉并易于理解。如果你不熟悉WebpackBabelNode.js,那这将是种恐怖的入门方式。

让我们开始创建一个基本的index.html文件。我们将在头部head中加载三个CDN资源 - ReactDOMBabel。我们还将创建一个idrootdiv,最后,我们将创建一个脚本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类来创建一个名为AppReact组件。

# 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 DOMrender()方法将我们创建的App类渲染到HTMLroot容器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,将看到我们创建的呈现给DOMh1标签。

hello world

太棒了!现在你完成了这一步,你可以看到React并没有那么让人着迷。只是一些JavaScript帮助教程库,我们将其加载到HTML中。

我们出于演示目的完成了此操作,但是从这里开始,我们将使用另一种方式:Create React App

创建React App

我刚刚使用的是将JavaScript库加载到静态HTML页面中并动态渲染ReactBabel的方法不是很有效,并很难维护。

幸运的是,Facebook创建了Create React App,该环境预先配置了构建React所需要的一切。它将创建一个实时开发服务器,使用webpack自动编译ReactJSXES6,自动为CSS文件加前缀,并使用ESLint测试和警告代码中的错误。

要设置create-react-app,你要在终端运行以下代码,该代码位于你希望项目所在的目录。请确保你安装了5.2以上版本的Node.js

npx create-react-app react-tutorial

安装完成之后,移至新创建的目录并启动项目。

cd react-tutorial
npm start

运行此命令之后,新的React应用程序将在浏览器的localhost:3000弹出一个新窗口。

welcome to react

如果你查看项目结构,将会看到/public/src目录,以及常规的node_modules.gitignoreREADME.mdpackage.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.cssindex.js

对于index.css,我只是将原始Primitive CSS 的内容复制并粘贴到文件中。如果需要,可以使用Bootstrap或所需的任何CSS框架,或者什么都不用。我只是觉得更容易使用而已。

index.js中,我引入了ReactReactDOMCSS文件。

# 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 devtools

现在,我们拥有了实际开始使用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'

然后通过将其加载到Apprender()中,然后获得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已加载。

class component

现在,我们了解了什么是自定义类组件。我们可以反复使用此组件。但是,由于将数据硬编程(即写死)在其中,因此目前它并不太实用。

简单组件

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文件如下所示。请注意,TableHeaderTableBody组件都在同一个文件中,并且由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 />
}

然后,将所有数据移到对象数组中,就像我们引入基于JSONAPI一样。我们必须在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同步快速有效的方法。

inspect props

但是,此数据尚未在实际的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一样再次将其作为属性传递。

另外,由于事实证明,在我们的项目中仅由其自己的状态的组件是AppForm,因此最佳实际是将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() 方法的函数,否则它将尝试自动运行。

太棒了,现在我们有了删除按钮,我们可以通过删除字符来修改状态。

state demo

我删除了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的本地状态。

form state

太棒了。最后一步是允许我们实际提交该数据并更新父状态。我们将在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} />

就是这样!该应用程序已经完成了。我们可以在表中创建,添加和删除用户。由于TableTableBody已经从状态中拉出,因此将正确显示。

add_state

如果你有疑问,你可以在我的github上查看源码。

拉取API数据

React的一种非常常见的用法是从API提取数据。如果你不熟悉什么是API或者如何连接API,我建议你阅读下如何使用JavaScript连接API这篇文章,它将引导你了解什么是API以及如何将它们与原始的JavaScript一起使用。

作为一个小测试,我们可以创建一个新的Api.js文件,并在其中创建新的App。我们可以测试的公共APIWikipedia 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数据。

api data

还有其他生命周期的方法,但是这里将不再讨论它们。你可以在此处于阅读有关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并学下去。

参考&后话

@reng99 reng99 added the blog a single blog label Feb 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blog a single blog
Projects
None yet
Development

No branches or pull requests

1 participant