React 入门
目录
(1)静态HTML文件
(2)创建React应用
一、什么是React?
React是一个JavaScript库-最受欢迎的JavaScript库之一,在GitHub上有超过100,000个星。
React不是一个框架(与Angular不同,后者更自以为是)。
React是Facebook创建的一个开源项目。
React用于在前端构建用户界面(UI)。
React是MVC应用程序的视图层(模型视图控制器)
其中一个发生反应的最重要的方面是,你可以创建组件,这是一样的自定义,可重复使用的HTML元素,快速,高效地构建用户界面。React还使用state和props简化了数据的存储和处理方式。
二、React的安装方式
(1)静态HTML文件
第一种方法不是设置React的流行方法,也不是本教程其余部分的工作方式,但是如果您曾经使用过jQuery之类的库,它将是熟悉且易于理解的,如果您不熟悉Webpack,Babel和Node.js,那么这是最恐怖的入门方法。
让我们开始制作一个基本index.html
文件。我们将在head
React,React DOM和Babel中加载三个CDN 。我们还将创建一个div
名为的ID root
,最后我们将创建一个script
标签,您的自定义代码将在其中存在。
<!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类创建一个称为的React组件App
。
这是我们的完整代码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并没有那么让人着迷。只是一些JavaScript帮助程序库,我们可以将其加载到HTML中。
我们出于演示目的完成了此操作,但是从这里开始,我们将使用另一种方法:创建React App。
(2)创建React应用
我刚刚使用的将JavaScript库加载到静态HTML页面中并即时渲染React和Babel的方法不是很有效,并且很难维护。
幸运的是,Facebook创建了Create React App,该环境预先配置了构建React应用所需的一切。它将创建一个实时开发服务器,使用Webpack自动编译React,JSX和ES6,自动前缀CSS文件,并使用ESLint来测试和警告代码中的错误。
要进行设置create-react-app
,请在您的终端中运行以下代码,该代码位于您希望项目所在的目录。确保您具有5.2
或更高的Node.js。
npx create-react-app react-tutorial
安装完成后,移至新创建的目录并启动项目。
cd react-tutorial
npm start
一旦运行此命令,localhost:3000
新的React应用程序将弹出一个新窗口。
如果你考虑项目结构,你会看到一个/public
和/src
目录,与正规一起node_modules
,.gitignore
,README.md
,和package.json
。
在中/public
,我们的重要文件是index.html
,与index.html
我们之前制作的静态文件非常相似-仅是一个root
div。这次,没有库或脚本被加载。该/src
目录将包含我们所有的React代码。
要查看环境如何自动编译和更新您的React代码,请在中找到如下所示的行/src/App.js
:
这是我们的全部index.js
。这次,我们将Component
as作为React的属性加载,因此我们不再需要extend 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
,您将看到“你好,React!” 就像以前那样。我们现在有了React应用程序的开始。
三、React开发人员工具
有一个名为React Developer Tools的扩展,可以使您在使用React时的工作更加轻松。下载适用于Chrome的React DevTools或您希望使用的任何浏览器。
安装后,当您打开DevTools时,您将看到React的标签。单击它,您将能够在编写组件时检查它们。您仍然可以转到“元素”选项卡以查看实际的DOM输出。现在看来似乎没什么大不了的,但是随着应用程序变得越来越复杂,使用它的必要性也越来越高。
现在我们拥有了实际开始使用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。在幕后,它正在运行createElement
,它接受标签,包含属性的对象和组件的子代,并呈现相同的信息。下面的代码将具有与上面的JSX相同的输出。
const heading = React.createElement('h1', { className: 'site-heading' }, 'Hello, React!')
JSX实际上更接近JavaScript,而不是HTML,因此在编写时需要注意一些关键区别。
className
用于代替class
添加CSS类(class
JavaScript中的保留关键字)。JSX中的属性和方法为camelCase-
onclick
将变为onClick
。自闭合标签必须以斜杠结尾-例如
<img />
JavaScript表达式也可以使用大括号(包括变量,函数和属性)嵌入JSX内。
const name = 'Tania' const heading = <h1>Hello, {name}</h1>
JSX比在原始JavaScript中创建和添加许多元素更容易编写和理解,这也是人们如此热爱React的原因之一。
将 JSX 添加到项目
将 JSX 添加到项目中并不需要诸如打包工具或开发服务器那样复杂的工具。本质上,添加 JSX 就像添加 CSS 预处理器一样。唯一的要求是你在计算机上安装了 Node.js。
在终端上跳转到你的项目文件夹,然后粘贴这两个命令:
步骤 1: 执行
npm init -y
(如果失败,这是修复办法)步骤 2: 执行
npm install babel-cli@6 babel-preset-react-app@3
提示
我们在这里使用 npm 只是用来安装 JSX 预处理器,之后你不再需要它。React 和应用程序代码都可以继续使用
<script>
标签而不做任何更改。
运行 JSX 预处理器
创建一个名为 src
的文件夹并执行这个终端命令:
npx babel --watch src --out-dir . --presets react-app/prod
注意:
npx
不是拼写错误 —— 它是 npm 5.2+ 附带的 package 运行工具。如果你看到一个错误消息显示为:“You have mistakenly installed the
babel
package”,你可能错过了上一步。在同一个文件夹中执行它,然后重试。
不要等待它运行结束 —— 这个命令启动了一个对 JSX 的自动监听器。
如果此时你用这段 JSX 入门代码创建一个 src/like_button.js
文件,监听器会创建一个预处理过的 like_button.js
文件,它包含了适用于浏览器的普通 JavaScript 代码。当你编辑带有 JSX 的源文件时,转换过程将自动重新执行。
这样,在旧浏览器上也能够使用现代 JavaScript 的语法特性,比如 class。我们刚才使用的工具叫 Babel,你可以从它的文档中了解更多。
如果你认为你已经习惯了构建工具,并希望它们能为你做更多事,下一章节描述了一些最流行和易上手的工具链。如果不使用构建工具 —— 直接以 scripts 标签的方式也可以很好地完成工作!
五、组件
到目前为止,我们已经创建了一个组件- App
组件。React中的几乎所有内容都由组件组成,这些组件可以是类组件或简单组件。
大多数React应用程序都有许多小组件,所有内容都加载到主App
组件中。组件也经常会获得自己的文件,因此让我们更改项目即可。
App
从中删除该类index.js
,因此它看起来像这样。
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
,并将组件放入其中。
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
,我们可以先将其导入到表中,以加载表:
src / App.js
import Table from './Table'
然后将其加载到的render()
中App
,在此之前我们已经有了“ 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
加载的环境。
现在,我们已经了解了什么是自定义类组件。我们可以反复使用此组件。但是,由于数据已被硬编码到其中,因此目前它并不太有用。
简单组件
React中的另一种类型的组件是simple component,它是一个函数。该组件不使用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
文件将如下所示。请注意,TableHeader
和TableBody
组件都在同一个文件中,并由Table
类组件使用。
src / Table.js
const TableHeader = () => { ... } const TableBody = () => { ... } class Table extends Component { render() { return ( <table> <TableHeader /> <TableBody /> </table> ) } }
一切都应该像以前一样出现。如您所见,组件可以嵌套在其他组件中,并且简单和类组件可以混合使用。
一个类组件必须包含
render()
,并且return
只能返回一个父元素。
作为总结,让我们比较一个简单的组件和一个类组件。
简单组件
const SimpleComponent = () => { return <div>Example</div> }
类组件
class ClassComponent extends Component { render() { return <div>Example</div> } }
请注意,如果return
包含在一行中,则不需要括号。
六、Props
现在,我们有一个很棒的Table
组件,但是数据正在被硬编码。关于React的重要问题之一是它如何处理数据,它使用属性(称为props)和状态来处理数据。现在,我们将专注于使用道具处理数据。
首先,让我们从TableBody
组件中删除所有数据。
src / Table.js
const TableBody = () => { return <tbody /> }
然后,将所有数据移动到对象数组中,就像我们引入基于JSON的API一样。我们必须在中创建此数组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表达式,因此将大括号括起来。
return ( <div className="container"> <Table characterData={characters} /> </div> )
现在数据已经传递到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
。我们只传递一个道具characterData,所以我们将使用它this.props.characterData
来检索该数据。
我将使用ES6属性速记来创建一个包含的变量this.props.characterData
。
由于我们的Table
组件实际上由两个较小的简单组件组成,因此我将TableBody
再次通过props 将其传递给。
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作为参数传递,并映射通过数组以返回数组中每个对象的表行。该映射将包含在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中创建列表时,应始终使用键,因为它们有助于识别每个列表项。我们还将在需要操纵列表项的时刻看到这是必要的。
道具是将现有数据传递到React组件的有效方法,但是该组件无法更改道具-它们是只读的。在下一节中,我们将学习如何使用状态来进一步控制React中的数据处理。
七、state
现在,我们将字符数据存储在变量中的数组中,并将其作为道具传递。这是一个很好的开始,但是请想象一下,如果我们希望能够从数组中删除一个项目。使用props,我们有一种单向数据流,但是有了状态,我们可以更新组件中的私有数据。
您可以将状态视为无需保存或修改而不必添加到数据库的任何数据-例如,在确认购买之前在购物车中添加和删除商品。
首先,我们将创建一个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 }, ], } }
我们的数据已正式包含在该州中。由于我们希望能够从表中删除字符,因此我们将removeCharacter
在父App
类上创建一个方法。
要检索状态,我们将this.state.characters
使用与以前相同的ES6方法。要更新状态,我们将使用this.setState()
,用于处理状态的内置方法。我们将根据通过的数组对数组进行过滤index
,然后返回新数组。
您必须使用this.setState()
来修改数组。简单地将新值应用到this.state.property
将不起作用。
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> ) }
由于我们将其向下传递TableBody
自Table
,因此我们将不得不像道具数据一样再次将其作为道具传递。
src / Table.js
class Table extends Component { render() { const { characterData, removeCharacter } = this.props return ( <table> <TableHeader /> <TableBody characterData={characterData} removeCharacter={removeCharacter} /> </table> ) } }
这就是我们在removeCharacter()
方法中定义的索引的输入位置。在TableBody
组件中,我们将键/索引作为参数传递,因此过滤器函数知道要删除的项目。我们将使用创建一个按钮并将其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()
方法的函数,否则它将尝试自动运行。
太棒了 现在我们有了删除按钮,我们可以通过删除字符来修改状态。
我删除了Mac。
现在您应该了解如何初始化状态以及如何修改状态。
八、提交表格数据
现在我们已经将数据存储在状态中,并且可以从状态中删除任何项目。但是,如果我们希望能够添加新数据来说明呢?在实际的应用程序中,您更有可能从空状态开始并添加到空状态,例如待办事项列表或购物车。
首先,让state.characters
我们从中删除所有硬编码数据,因为我们现在将通过表单进行更新。
src / App.js
class App extends Component { state = { characters: [], } }
现在,让我们继续Form
在一个名为的新文件中创建一个组件Form.js
。我们将创建一个类组件,并在constructor()
其中使用,到目前为止我们还没有做过。我们需要constructor()
使用this
,并接收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
状态,然后状态会更新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>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
,我们可以在表格下方呈现表单。
src / App.js
return ( <div className="container"> <Table characterData={characters} removeCharacter={this.removeCharacter} /> <Form /> </div> )
现在,如果我们转到应用程序的前端,将会看到尚未提交的表单。更新一些字段,您将看到Form
正在更新的本地状态。
最后一步是允许我们实际提交该数据并更新父状态。我们将创建一个名为的函数handleSubmit()
,App
该函数将使用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} />
就是这样!该应用程序已完成。我们可以在表中创建,添加和删除用户。由于Table
和TableBody
已经从状态中拉出,因此它将正确显示。
九、提取API数据
React的一种非常常见的用法是从API提取数据。如果您不熟悉什么是API或如何连接API,我建议您阅读如何使用JavaScript连接到API,这将带您了解什么是API以及如何将它们与原始JavaScript一起使用。
作为一个小测试,我们可以创建一个Api.js
文件,然后App
在其中创建一个新文件。我们可以测试的公共API是Wikipedia API,我这里有一个URL端点,可以进行随机*搜索。您可以转到该链接查看API-并确保在浏览器上安装了JSONView。
我们将使用JavaScript的内置Fetch从该URL端点收集数据并显示它。您可以我们创建的应用程序,这个测试文件之间仅通过更改URL中的切换index.js
- import App from './Api';
。
我不会逐行解释此代码,因为我们已经学习了有关通过状态数组创建组件,渲染和映射的知识。该代码的新方面是componentDidMount()
React生命周期方法。生命周期是在React中调用方法的顺序。挂载是指要插入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代码并将其放在某个目录的根目录中,则只需运行以下行:
npm run build
这将创建一个build
包含您的应用程序的文件夹。将文件夹的内容放在任何地方,就可以完成!
我们还可以更进一步,并为我们部署npm。我们将构建到GitHub页面,因此您已经必须熟悉Git并在GitHub上获取代码。
确保您退出了本地React环境,因此该代码当前未在运行。首先,我们要在中添加一个homepage
字段package.json
,该字段具有我们希望应用程序继续存在的URL。
package.json
"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
- 点赞
- 收藏
- 关注作者
评论(0)