视频教程

本文章在B站配有视频教程

课程目标

  • 了解最常用的React概念和相关术语,例如JSX,组件,属性(Props),状态(state)。
  • 构建一个非常简单的React应用程序,以阐述上述概念。

最终效果

创建React应用

helloworld

(1)安装node.js     官网链接

(2)打开cmd 窗口 输入

  1. npm install --g create-react-app
  2. npm install --g yarn

(-g 代表全局安装)

如果安装失败或较慢。需要换源,可以使用淘宝NPM镜像,设置方法为:npm config set registry https://registry.npm.taobao.org,设置完成后,

重新执行

  1. cnpm install --g create-react-app
  2. cnpm install --g yarn

安装 creat-react-app 功能组件,该组件可以用来初始化一个项目, 即 按照一定的目录结构,生成一个新项目

(3)在你想创建项目的目录下  例如 D:/project/ 打开cmd命令 输入

  1. create-react-app react-tutorial

去使用creat-react-app命令创建名字是react-tutorial的项目

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

  1. cd react-tutorial
  2. yarn start

一旦运行此命令,localhost:3000新的React应用程序将弹出一个新窗口。

项目目录结构

一个/public和/src目录,以及node_modules,.gitignore,README.md,和package.json。

在目录/public中,重要文件是index.html,其中一行代码最重要

  1. <div id="root"></div>

该div做为我们整个应用的挂载点

/src目录将包含我们所有的React代码。

要查看环境如何自动编译和更新您的React代码,请找到文件/src/App.js

将其中的

  1. <a
  2. className="App-link"
  3. href="https://reactjs.org"
  4. target="_blank"
  5. rel="noopener noreferrer"
  6. >
  7. Learn React
  8. </a>

修改为

  1. <a
  2. className="App-link"
  3. href="https://reactjs.org"
  4. target="_blank"
  5. rel="noopener noreferrer"
  6. >
  7. 和豆约翰 Learn React
  8. </a>

保存文件后,您会注意到localhost:3000编译并刷新了新数据。



现在删除/src目录中的所有文件,我们将从头开始创建自己的项目文件。

开始我们的mini项目

1.新建文件index.css

我们就拷贝index.css文件的全部内容(css不是我们这次课程的重点).

2.新建文件index.js

在index.js中,我们将导入React,ReactDOM和CSS文件。

src / index.js

  1. import React, { Component } from 'react'
  2. import ReactDOM from 'react-dom'
  3. import './index.css'

创建App组件,在render方法中返回一个div(这里是JSX语法)

src / index.js

  1. class App extends Component {
  2. render() {
  3. return (
  4. <div className="App">
  5. <h1>Hello, React!</h1>
  6. </div>
  7. )
  8. }
  9. }

最后,我们将App渲染到根节点。

src / index.js

  1. ReactDOM.render(<App />, document.getElementById('root'))

index.js完整代码

  1. import React, { Component } from 'react'
  2. import ReactDOM from 'react-dom'
  3. import './index.css'
  4. class App extends Component {
  5. render() {
  6. return (
  7. <div className="App">
  8. <h1>Hello, React!</h1>
  9. </div>
  10. )
  11. }
  12. }
  13. ReactDOM.render(<App />, document.getElementById('root'))

在浏览器输入localhost:3000,您将看到“你好,React!

JSX:JavaScript + XML

如您所见,我们在React代码中一直使用看起来像HTML的东西,但它并不是完全HTML。这是JSX,代表JavaScript XML。

使用JSX,我们可以编写看起来像HTML的内容,也可以创建和使用我们自己的类似XML的标签。

以下是JSX分配给变量的样子:

  1. const heading = <h1 className="site-heading">Hello, React</h1>

编写React并非必须使用JSX。在幕后,它正在运行createElement,它接受标签,包含属性象和组件的后代,并呈现相同的信息。下面的代码将具有与上面的JSX相同的输出。

  1. const heading = React.createElement('h1', { className: 'site-heading' }, 'Hello, React!')

JSX实际上更接近JavaScript,而不是HTML,因此在编写时需要注意一些关键区别。

  • className用于代替class添加CSS类(classJavaScript中的保留关键字)。
  • JSX中的属性和方法为camelCase(驼峰表示法) - onclick将变为onClick。
  • 自闭合标签必须以斜杠结尾-例如
  • JavaScript表达式也可以使用大括号(包括变量,函数和属性)嵌入JSX内。
  1. const name = 'Tania'
  2. const heading = <h1>Hello, {name}</h1>

JSX比在原生JavaScript中创建和添加元素更容易编写和理解,这也是人们如此热爱React的原因之一。

组件

到目前为止,我们已经创建了一个组件- App组件。React中的几乎所有内容都由组件组成,这些组件可以是类组件或简单组件。

大多数React应用程序都有许多小组件,所有内容都加载到主App组件中。

组件经常定义在单个js文件中,

接下来让我们更改项目。从index.js中删除App类:

index.js

  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. import App from './App'
  4. import './index.css'
  5. ReactDOM.render(<App />, document.getElementById('root'))

我们将创建一个新文件App.js,并将组件放入其中。

  1. import React, { Component } from 'react'
  2. class App extends Component {
  3. render() {
  4. return (
  5. <div className="App">
  6. <h1>Hello, React!</h1>
  7. </div>
  8. )
  9. }
  10. }
  11. export default App

我们将组件导出为App并将其加载到中index.js。将组件分成文件不是强制性的,但是如果不这样做的话,应用程序将开始变得笨拙和混乱。

类组件

让我们创建另一个组件。我们将创建一个表格。制作Table.js,并用以下数据填充。

src / Table.js

  1. import React, { Component } from 'react'
  2. class Table extends Component {
  3. render() {
  4. return (
  5. <table>
  6. <thead>
  7. <tr>
  8. <th>Name</th>
  9. <th>Job</th>
  10. </tr>
  11. </thead>
  12. <tbody>
  13. <tr>
  14. <td>Charlie</td>
  15. <td>Janitor</td>
  16. </tr>
  17. <tr>
  18. <td>Mac</td>
  19. <td>Bouncer</td>
  20. </tr>
  21. <tr>
  22. <td>Dee</td>
  23. <td>Aspiring actress</td>
  24. </tr>
  25. <tr>
  26. <td>Dennis</td>
  27. <td>Bartender</td>
  28. </tr>
  29. </tbody>
  30. </table>
  31. )
  32. }
  33. }
  34. export default Table

我们创建的该组件是一个自定义类组件。自定义组件名称首字母大写,以区别于常规HTML元素。回到App.js,我们可以先将表格组件导入,以加载表格组件:

src / App.js

  1. import Table from './Table'

然后将其加载到App类的render()函数中,在此之前我们已经有了“ Hello,React!”。还更改了外部容器的类名。

  1. import React, { Component } from 'react'
  2. import Table from './Table'
  3. class App extends Component {
  4. render() {
  5. return (
  6. <div className="container">
  7. <Table />
  8. </div>
  9. )
  10. }
  11. }
  12. export default App

现在,我们已经了解了什么是自定义类组件。我们复用此组件。但是,由于数据已被硬编码到其中,因此目前它并不太有用。

简单组件

React中的另一种类型的组件是simple component,它是一个函数。该组件不使用class关键字。让我们为Table组件制作两个简单的子组件-一个表头和一个表主体。

我们将使用ES6箭头表达式来创建这些简单的组件。首先,表头:

src / Table.js

  1. const TableHeader = () => {
  2. return (
  3. <thead>
  4. <tr>
  5. <th>Name</th>
  6. <th>Job</th>
  7. </tr>
  8. </thead>
  9. )
  10. }

然后是表主体。

src / Table.js

  1. const TableBody = () => {
  2. return (
  3. <tbody>
  4. <tr>
  5. <td>Charlie</td>
  6. <td>Janitor</td>
  7. </tr>
  8. <tr>
  9. <td>Mac</td>
  10. <td>Bouncer</td>
  11. </tr>
  12. <tr>
  13. <td>Dee</td>
  14. <td>Aspiring actress</td>
  15. </tr>
  16. <tr>
  17. <td>Dennis</td>
  18. <td>Bartender</td>
  19. </tr>
  20. </tbody>
  21. )
  22. }

现在,我们的Table.js文件将如下所示。请注意,TableHeader和TableBody组件都在同一个文件中,并由Table类组件使用。

src / Table.js

  1. import React, { Component } from 'react'
  2. const TableHeader = () => {
  3. return (
  4. <thead>
  5. <tr>
  6. <th>Name</th>
  7. <th>Job</th>
  8. </tr>
  9. </thead>
  10. )
  11. }
  12. const TableBody = () => {
  13. return (
  14. <tbody>
  15. <tr>
  16. <td>Charlie</td>
  17. <td>Janitor</td>
  18. </tr>
  19. <tr>
  20. <td>Mac</td>
  21. <td>Bouncer</td>
  22. </tr>
  23. <tr>
  24. <td>Dee</td>
  25. <td>Aspiring actress</td>
  26. </tr>
  27. <tr>
  28. <td>Dennis</td>
  29. <td>Bartender</td>
  30. </tr>
  31. </tbody>
  32. )
  33. }
  34. class Table extends Component {
  35. render() {
  36. return (
  37. <table>
  38. <TableHeader />
  39. <TableBody />
  40. </table>
  41. )
  42. }
  43. }
  44. export default Table

运行结果不变。如您所见,组件可以嵌套在其他组件中,并且简单和类组件可以混合使用。

一个类组件必须包含render(),并且return只能返回一个父元素。

作为总结,让我们比较一个简单的组件和一个类组件:.

简单组件

  1. const SimpleComponent = () => {
  2. return <div>Example</div>
  3. }

类组件

  1. class ClassComponent extends Component {
  2. render() {
  3. return <div>Example</div>
  4. }
  5. }

props

我们的Table组件,数据是硬编码的。关于React的重要问题之一是它如何处理数据,它使用属性(props)和状态(state)来处理数据。现在,我们将专注于使用props处理数据。

首先,让我们从TableBody组件中删除所有数据。

src / Table.js

  1. const TableBody = () => {
  2. return (
  3. <tbody></tbody>
  4. )
  5. }

然后,将所有数据定义到一个对象数组中:

src / App.js

  1. class App extends Component {
  2. render() {
  3. const characters = [
  4. {
  5. name: 'Charlie',
  6. job: 'Janitor',
  7. },
  8. {
  9. name: 'Mac',
  10. job: 'Bouncer',
  11. },
  12. {
  13. name: 'Dee',
  14. job: 'Aspring actress',
  15. },
  16. {
  17. name: 'Dennis',
  18. job: 'Bartender',
  19. },
  20. ]
  21. return (
  22. <div className="container">
  23. <Table />
  24. </div>
  25. )
  26. }
  27. }

接下来,我们将通过属性characterData将数据传递给子组件Table,传递的数据是characters变量,由于它是JavaScript表达式,因此使用大括号括起来。

  1. return (
  2. <div className="container">
  3. <Table characterData={characters} />
  4. </div>
  5. )

现在数据已经传递到Table组件,我们可以在Table组件通过this.props中访问到。

src / Table.js

  1. class Table extends Component {
  2. render() {
  3. const { characterData } = this.props
  4. return (
  5. <table>
  6. <TableHeader />
  7. <TableBody characterData={characterData} />
  8. </table>
  9. )
  10. }
  11. }

由于Table组件实际上由两个较小的简单组件组成,因此再次通过props 将其传递给子组件TableBody

我们将把props作为参数传递给简单组件TableBody ,并通过数组的map方法将数据映射为jsx片段的集合。该jsx片段集合将包含在rows变量中,我们将其作为表达式返回。

  1. const TableBody = props => {
  2. const rows = props.characterData.map((row, index) => {
  3. return (
  4. <tr key={index}>
  5. <td>{row.name}</td>
  6. <td>{row.job}</td>
  7. </tr>
  8. )
  9. })
  10. return <tbody>{rows}</tbody>
  11. }

您会注意到我已经向每个表行添加了一个键索引。在React中创建列表时,应始终使用,因为它们有助于识别每个列表项。我们还将在需要操纵列表项的时刻看到这是必要的。

props是将现有数据传递到React组件的有效方法,但是该组件无法更改props-它们是只读的。在下一节中,我们将学习如何使用状态(state)来进一步控制React中的数据处理。

state

我们将表格数据存储在数组变量中,并将其作为props传递。但是如果我们希望能够从数组中删除一个项目,就做不到了。props,是一种单向数据流,子组件不能进行修改。但是有了state,我们就可以更新组件中的私有数据。

您可以将state视为可以在组件内增删改的而不必添加到数据库的任何临时数据-例如,在确认购买之前在购物车中添加和删除的购物车项目。state改变后,绑定state数据的视图会自动更新。

首先,我们将创建一个state对象。

src / App.js

  1. class App extends Component {
  2. state = {}
  3. }

在state对象中定义属性,保存我们所需的数据。

src / App.js

  1. class App extends Component {
  2. state = {
  3. characters: [],
  4. }
  5. }

将我们之前创建的对象的整个数组移到中state.characters。

  1. class App extends Component {
  2. state = {
  3. characters : [
  4. {
  5. name: 'Charlie',
  6. job: 'Janitor',
  7. },
  8. {
  9. name: 'Mac',
  10. job: 'Bouncer',
  11. },
  12. {
  13. name: 'Dee',
  14. job: 'Aspring actress',
  15. },
  16. {
  17. name: 'Dennis',
  18. job: 'Bartender',
  19. },
  20. ]
  21. }
  22. }

在App.js中,创建removeCharacter方法来删除一个项目

  1. removeCharacter = index => {
  2. const { characters } = this.state
  3. this.setState({
  4. characters: characters.filter((character, i) => {
  5. return i !== index
  6. }),
  7. })
  8. }

您必须使用this.setState()来修改数组。简单地将新值应用到this.state.property将不起作用。

现在,我们必须将该函数传递给组件。我们会将removeCharacter函数作为属性传递给Table。

src/App.js

  1. render() {
  2. const { characters } = this.state
  3. return (
  4. <div className="container">
  5. <Table characterData={characters} removeCharacter={this.removeCharacter} />
  6. </div>
  7. )
  8. }

由于Table组件,并不需要自己的state数据对象,所以,我们将它改造成简单组件,并将removeCharacter函数继续向TableBody 子组件传递:

src/Table.js

  1. const Table = props => {
  2. const { characterData, removeCharacter } = props
  3. return (
  4. <table>
  5. <TableHeader />
  6. <TableBody characterData={characterData} removeCharacter={removeCharacter} />
  7. </table>
  8. )
  9. }

在TableBody组件中,我们将键/索引作为参数传递,因为removeCharacter函数知道要删除的项目索引。我们创建一个按钮并将其onClick事件绑定removeCharacter函数;

src/Table.js

  1. <tr key={index}>
  2. <td>{row.name}</td>
  3. <td>{row.job}</td>
  4. <td>
  5. <button onClick={() => props.removeCharacter(index)}>Delete</button>
  6. </td>
  7. </tr>

onClick事件必须绑定为返回该removeCharacter()方法的函数,否则removeCharacter()将尝试不等按钮点击而自动运行。

新增表格数据

现在我们已经将数据存储在App.js组件的state对象中,并且可以从state对象中删除任何项目。但是,如何向state对象中添加数据呢?我们将通过一个表单组件来实现这个需求。

首先,state.characters中删除所有硬编码数据:

src / App.js

  1. class App extends Component {
  2. state = {
  3. characters: [],
  4. }
  5. }

创建新文件Form.js。

  1. import React, { Component } from 'react'
  2. class Form extends Component {
  3. initialState = {
  4. name: '',
  5. job: '',
  6. }
  7. state = this.initialState
  8. }

以前,React类组件有必要包括一个constructor(),但是现在不再需要。

此表单的目标是Form每次更改表单中的字段时都会更新本组件(Form)的state,并且在我们提交表单时,所有数据都将传递给App组件的state,然后Table组件会自动更新。

首先定义input控件的onChange事件处理函数:

src / Form.js

  1. handleChange = event => {
  2. const { name, value } = event.target
  3. this.setState({
  4. [name]: value,
  5. })
  6. }

Form组件的render函数实现如下:

src / Form.js

  1. render() {
  2. const { name, job } = this.state;
  3. return (
  4. <form>
  5. <label htmlFor="name">Name</label>
  6. <input
  7. type="text"
  8. name="name"
  9. id="name"
  10. value={name}
  11. onChange={this.handleChange} />
  12. <label htmlFor="job">Job</label>
  13. <input
  14. type="text"
  15. name="job"
  16. id="job"
  17. value={job}
  18. onChange={this.handleChange} />
  19. </form>
  20. );
  21. }
  22. export default Form;

在App.js,导入Form:

  1. import Form from './Form';
  2. return (
  3. <div className="container">
  4. <Table characterData={characters} removeCharacter={this.removeCharacter} />
  5. <Form />
  6. </div>
  7. )

最后一步是实现提交该数据并更新父组件状态。我们将创建一个名为handleSubmit()的函数,该函数将使用[ES6扩展运算符]语法来更新状态。

src / App.js

  1. handleSubmit = character => {
  2. this.setState({ characters: [...this.state.characters, character] })
  3. }

确保我们将其作为参数传递给Form

  1. <Form handleSubmit={this.handleSubmit} />

现在,在Form中,我们将创建一个名为submitForm()的方法,该方法将调用传进来的handleSubmit函数,并将Form的state作为character参数传递。它还将Form的state重置为初始状态,以在表单提交后清除表单信息。

src / Form.js

  1. submitForm = () => {
  2. this.props.handleSubmit(this.state)
  3. this.setState(this.initialState)
  4. }

最后,我们将在Form.js中添加一个提交按钮以提交表单,点击将调用我们刚定义的submitForm函数。

src / Form.js

  1. <input type="button" value="Submit" onClick={this.submitForm} />

就是这样!该应用程序已完成。

完整代码

一篇文章快速入门React框架的更多相关文章

  1. 快速入门react

    安装react npm install creat-react-app -g这里直接安装react的一个脚手架,里面包含了要用到的许多东西,帮助快速入门react 创建新项目 create-react ...

  2. 快速入门GreenDao框架并实现增删改查案例

    大家的项目中不可避免的使用到SQLite,为此我们要花费心思编写一个增删改查框架.而一个好的ORM框架则能够给我们带来极大的方便,今天给大家讲解一个非常火热的ORM-GreenDao. 基本概念 Gr ...

  3. 《Spring3.0就这么简单》第1章快速入门

    问题 [如何将jsp中传递到HttpServletRequest的参数,自动装配到Java对象中] [成功] public void setUsernAme(String username) < ...

  4. 【零基础】快速入门爬虫框架HtmlUnit

    迅速的HtmlUnit htmlunit是一款开源的web页面分析工具,理论上来说htmlunit应用于网页的自动化测试,但是相对来说更多人使用它来进行小型爬虫的快速开发.使用htmlunit进行爬虫 ...

  5. 《C++ 101条建议》学习笔记——第一章快速入门

    1.C++程序组成:a.编译指示,由#开始,不由分号结束.只是影响编译过程.b.声明语句,影响编译过程,编译结果中并不会生成对应的指令.只是告诉编译器一些信息.c.可执行过程语句,生成对应的指令.包括 ...

  6. 一篇文章快速搞懂 Atomic(原子整数/CAS/ABA/原子引用/原子数组/LongAdder)

    前言 相信大部分开发人员,或多或少都看过或写过并发编程的代码.并发关键字除了Synchronized,还有另一大分支Atomic.如果大家没听过没用过先看基础篇,如果听过用过,请滑至底部看进阶篇,深入 ...

  7. 一篇文章快速搞懂Qt文件读写操作

    导读:Qt当中使用QFile类对文件进行读写操作,对文本文件也可以与QTextStream一起使用,这样读写操作会更加简便.QFileInfo可以用来获取文件的信息.QDir可以用于对文件夹进行操作. ...

  8. 一文让你快速入门pytest框架

    pytest是什么 官方文档描述: pytest is a framework that makes building simple and scalable tests easy. Tests ar ...

  9. Android初级教程理论知识(第一章快速入门)

    一.综合介绍. Android项目的目录结构 Activity:应用被打开时显示的界面 src:项目代码 R.java:项目中所有资源文件的资源id Android.jar:Android的jar包, ...

随机推荐

  1. mybatis association的使用

    在上一篇文章中介绍了collection的使用以及java bean,表的结构,今天进行association使用的学习,在多对一的映射关系中,查询到多的一方顺带查询出一的一方是常见的!在此例子中,在 ...

  2. ql的python学习之路-day2

    python中所有字符串操作 , )))), ))))#返回50个长度的字符串,不够左边就以0补充,可以用在十六进制补位(不常用)运行结果: My name is qinjiaxi---------- ...

  3. 「雕爷学编程」Arduino动手做(18)---太阳能电池模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  4. 为什么Tableviewcell创建时可以不判空

    dequeueReuseableCellWithIdentifier:与dequeueReuseableCellWithIdentifier:forIndexPath:的区别: 前者不必向tableV ...

  5. UVA10529 Dumb Bones (完成度:40%)

    题目链接:https://vjudge.net/problem/UVA-10529 知识点: 概率与期望,DP. 题目大意: 现要放置 \(n\) 个多米诺骨牌,且每放置一块多米诺骨牌有 \(P_l\ ...

  6. Yii2.0 URL美化功能Nginx与Apache配置文件

    NGinx: location / { index index.html index.htm index.php; try_files $uri $uri/ /index.php$is_args$ar ...

  7. Swiper的jquery动态渲染不能滑动

    <!-- 下面俩行代码就是解决异步加载数据导致swiper不轮播的关键 --> observer: true,//修改swiper自己或子元素时,自动初始化swiper observePa ...

  8. 循序渐进VUE+Element 前端应用开发(2)--- Vuex中的API、Store和View的使用

    在我们开发Vue应用的时候,很多时候需要记录一些变量的内容,这些可以用来做界面状态的承载,也可以作为页面间交换数据的处理,处理这些内容可以归为Vuex的状态控制.例如我们往往前端需要访问后端数据,一般 ...

  9. Istio Gateway网关

    Istio Ingress Gateway Istio 服务网格中的网关 使用网关为网格来管理入站和出站流量,可以让用户指定要进入或离开网格的流量. 使用网关为网格来管理入站和出站流量,可以让用户指定 ...

  10. C#正则表达式基础

    namespace ---> System.Text.RegularExpressions. static void Main(string[] args) { // if (IsInputMa ...