猿技术React.js 基础概念一览
Posted 优才网
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了猿技术React.js 基础概念一览相关的知识,希望对你有一定的参考价值。
去年我写过一本100多页的学习 React.js 的书,今年要挑战一下自己把那本书精炼成Medium上的一篇文章。
这篇文章不会包含什么是 React 或者为什么要学习 React 这样的内容,这篇文章是对于已经熟悉 javascript 和 DOM API 基础的人员的一个实践入门。
下面的所有代码示例都有标签索引,示例只是各种概念的一个展示。大多数的示例都可以用一种更好的方法写出来。
准则 #1: React 的所有内容都是关于组件的
React 是围绕可重用组件的概念设计的,定义所有的小组件,然后将小组件合成大组件。
所有组件不管大小都是可重用的,而且也是跨工程的。
一个组件的最简单的形式是一个 JavaScript 函数:
标签 button 里面的大括号的意思在后边说明,ReactDOM 也将在后边内容解释。如果想要测试这个例子和后边所有的代码例子,你需要上边的 render 函数。
ReactDOM.render 的第二个参数是 React 将要挂载的目标 DOM 元素。在 jsComplete REPL 中,只能使用特殊的变量 mountNode 。
Example 1 的注意事项:
组件名必须首字母大写。由于需要处理混合的 html 元素和 React 元素,所以组件名必须首字母大写,小写的名称留给 HTML 元素。事实上,如果把上边的 React 组件名字改为 “button” , ReactDOM 将会忽略该函数并渲染一个普通的空 HTML 按钮。
像 HTML 元素一样,每个组件都接收一个属性列表,在 React 里面这个列表被称作 props 。通过函数组件,可以对 props 传递任何数据。
上边的 Button 组件返回里面写了一段很奇怪的类似 HTML 的代码,这段代码不是 JavaScript 代码,也不是 HTML 代码,也不是 React.js 。这种代码格式如此流行以至于 React 应用将其作为默认的代码语言。这种语言叫 JSX ,是 JavaScript 的一个扩展。 JSX 也是一种折中的语言!尝试在上边代码中返回另一种 HTML 元素,看一下 JSX 是怎样被支持的(例如返回一个文本输入框)。
准则 #2: 什么是flux的JSX?
上面的例子1可以用没有JSX的纯React.js编写,如下所示:
createElement函数是React顶级API的主要函数。这是你需要学习的7件事情中的1件。这就是React API的多小。
就像DOM本身具有一个document.createElement函数来创建一个由标签名称指定的元素一样,React的createElement函数是一个更高级的函数,可以执行document.createElement的操作。但它也可以用来创建一个元素来表示一个React组件。当我们使用上面例2中的Button组件时,我们做了后者。
与document.createElement不同的是,React的createElement接受第二个参数后的动态数量的参数来表示创建的元素的子元素。所以createElement实际上创建了一棵tree。
下边是一个创建树的例子:
其中有一些值得注意的地方:
InputForm 是一个 React 元素,不是一个 React 组件。这就是为什么在 ReactDOM.rander 中直接使用 InputForm 而不写成 <InputForm /> 的原因。
函数 React.createElement 在前两个参数后面还可以接收多个参数。从第三个参数开始的所有参数组成要创建的元素的子元素列表。
因为是 JavaScript 代码,React.createElement 函数可以嵌套调用。
如果要创建的元素没有属性或者 props 需要设置,React.createElement 的第二个参数可以为空。
HTML 元素可以和 React 组件混用,可以将 HTML 元素看成是 React 的内建组件。
React API 很贴近 DOM API ,所以在 input 元素里面需要使用 className 代替 class 。由于 React API 很优秀,窃希望 React API 可以成为 DOM API 一部分。
上边的代码是包含 React 库浏览器解析的代码,浏览器并不处理任何 JSX 代码。人类喜欢处理 HTML 而不是一大堆的函数 createElement 调用(想想一下只能用 document.createElement 创建网页)。这就是 JSX 存在的原因。上边的代码可以使用一个非常类似 HTML 的语法来实现,而不是通过 React.createElement 实现:
上边的代码有个需要注意的地方:
上边的代码并不是 HTML 代码,里面依旧用 className 代替 class
虽然上边的代码类似 HTML ,但应该被认为是 JavaScript ,代码的结尾加了分号。
上边的代码就是(示例4) JSX 。传给浏览器的代码是示例 4 编译之后的版本示例 3 。示例 4 变成示例 3 需要使用预处理器将 JSX 代码转为 React.createElemnt 版本的代码。
通过 JSX 采用类似 HTML 的语法书写 React 组件是一个很好的想法。
标题的单词 “Flux” 使用来押韵的,“Flux”也是一个非常流行的 Facebook 应用框架。最著名的一个实现版本是 Redux 。Flux 完美的适用于 React 交互模式。
顺便说一下,JSX 可以独立使用,而不只是依赖 React 。
准则 #3:在 JSX 的任何地方都可以使用 JavaScript 表达式
可以将任何 JavaScript 表达式包含在大括号里放在 JSX 代码里面。
任何 JavaScript 表达式都可以放到 JSX 代码中的大括号里面类似于 JavaScript 模板语法中的插入语法${}。
JSX 内嵌 JavaScript 代码的限制:只能是表达式。例如不能使用 if 语句但是使用三元表达式是可以的。
JavaScript 变量也是表达式,所以当组件接收 props 列表( props 是可选的,RandomValue 组件没有),可以把 props 放到大括号里面嵌入 JSX 中,上边的 Button 组件就是这么做的(示例1)。
JavaScript 对象也是表达式,所以 JavaScript 对象也可以包含在大括号里面嵌入 JSX 代码中。这样虽然有点像两个大括号,但仅仅是一个对象放到了一个大括号里面。在 React 里面传递 CSS 对象的时候就是这么用的:
上边代码值得注意的是:1. message 是如何从 props 中解构出来。2.上边用一个对象来作为样式属性的值是一种特殊情况 (非HTML,只是类似DOM API),对象中定义样式值和在 JavaScript 定义样式值是一样的。
React 元素是一个函数调用,也是一个表达式,所以也可以放到 JSX 里面:
上边例子中,当有错误消息字符串传递给 MaybeError 组件的时候,MaybeError 组件会显示 ErrorDisplay 组件。{true}、{false}、{undefined} 和 {null} 在 React 里面是有效元素,不渲染任何事物。
JavaScript 集合方法(map, reduce, filter, concat等)返回的是表达式,所以也可以在 JSX 里面调用所有的集合方法。
上边例子中注意如何给 prop 属性 value 设置默认值。上边例子里面在一个 div 标签里面输出里一个数组表达式,这在 React 里面是可以的,React 会把数组里面每个元素都放到一个文本节点中。
准则 #4: 可以使用JavaScript 类书写React组件
对于简单的需求简单的函数组件很合适,有时候需要更复杂功能的组件。React也支持JavaScript类语法来创建组件。下面的例子就是示例1的类语法书写方式:
类语法是比较简单的,定义一个React组件类需要继承自React.Component(另一个需要学习的React上层API)。React类必须定义一个返回虚拟DOM对象的render()函数。每次使用上边的Button类的时候(例如<Button ... />),React会实例化一个基于该类组件的对象并将该对象放到DOM树里面。
每一个组件实例化的时候都会接收一个包含所有传递给该组件的所有数据的实例属性props,所以可以在JSX里面使用this.props.label来渲染上边示例的输出。
上边例子是使用该类组件生成的一个实例,可以按需求定制化该实例。例如可以用JavaScript constructor函数在组件创建之后定制实例,如下:
也可以在类里面定义类原型函数并在任何需要的地方包括在要返回的JSX输出中使用该函数:
示例11 需要注意的地方有:
handleClick函数使用了JavaScript中新的语法类字段语法。这种语法虽然在草案阶段,但由于多种原因这种方法是获取组件的挂载实例的最好选择(感谢箭头函数)。上边的代码想要运行需要使用类似于babel的编译器并且配置识别stage-2(或者类字段语法)选项编译之后才可以运行。JSComplete REPL预先做了配置。
clickCounter也是用类字段语法定义的实例变量,这样书写就完全可以不使用类构造函数。
当把handleClick函数赋给React属性onClick的时候并没有调用该函数,仅仅是传递了handleClick函数的一个引用。在该地方写成函数调用是React编程中经常遇到的一个错误。
准则 #5:React 事件:与 DOM 事件的两个不同点
处理 React 元素里面的事件的时候,与 DOM API 相比有两个重要的不同:
所有 React 元素属性(包括事件)都使用驼峰命名规则而不是小写,例如应该写成 onClick 而不是 onclick 。
需要传递实际的 JavaScript 函数索引作为 React 元素事件处理函数而不是字符串,例如应该写成 onClick={handleClick} 而不是 onClick=“handleClick” 。
React 用一个 React 对象包装 DOM 事件以优化事件处理性能。React 在事件处理器里面仍可以获得所有 DOM 事件对象的方法。React 将包装后的对象传递每一个事件调用。例如,想禁止 form 表单默认的提交事件可以采用下面的做法:
准则#6:每个React组件都有一个故事
以下内容仅适用于类组件(那些扩展了React.Component的组件)。函数组件有一个稍微不同的故事。
首先,我们为React定义一个模板,以从组件创建元素。
然后,我们指示React在某处使用它。例如,在另一个组件的rendercall中,或者使用ReactDOM.render。
然后,React实例化一个元素并给它一组我们可以通过this.props访问的props。那些props正是我们在上面第二步所传递的。
由于它是全部的JavaScript,因此将调用构造函数方法(如果已定义)。这是我们所说的第一个组件生命周期方法。
React然后计算渲染方法(虚拟DOM节点)的输出。
由于这是React首次渲染元素,因此React将与浏览器(代表我们使用DOM API)在那里显示元素。这个过程通常被称为挂载中。
React然后调用另一个称为componentDidMount的生命周期方法。例如,我们可以使用这种方法在DOM上做一些我们现在知道存在于浏览器中的东西。在此生命周期方法之前,我们所使用的DOM都是虚拟的。
一些组件故事在这里结束。其他组件由于各种原因从浏览器DOM卸载。就在后者发生之前,React调用另一个生命周期方法componentWillUnmount。
任何挂载元素的状态可能会改变。该元素的父母可能会重新呈现。无论哪种情况,被挂载的元素都可能会收到一组不同的props。神奇的反应发生在这里,我们实际上开始需要在这一点上的React!在此之前,我们根本就不需要React。
这个组件的故事在继续,但是在这之前,我们需要了解这个我所说的状态。
准则#7:React组件可以有一个私有状态
以下内容也仅适用于类组件。我有没有提到一些人称只做展现的组件是哑巴?
状态类字段是任何React类组件中的特殊字段。 React监视每个组件状态以进行更改。但是为了让React高效地执行,我们必须通过另一个React API来更改状态字段,我们需要学习this.setState:
这里是理解的关键例子。它将基本完成您对React方式的基本知识。在这个例子之后,还有一些你需要学习的小东西,但是从这个角度来说,大部分是你和你的JavaScript技能。
让我们来看看例13,从类字段开始。它有两个。特殊状态字段用一个保存clickCounter(从0开始)的对象和一个以new Date()开始的currentTimestamp初始化。
第二个类字段是一个handleClick函数,我们将其传递给render方法中button元素的onClick事件。 handleClick方法使用setState修改这个组件实例状态。注意到这一点。
我们修改状态的另一个地方是在我们在componentDidMount生命周期方法内开始的间隔计时器内。它每秒钟都会触发一次,并对this.setState执行另一个调用。
在渲染方法中,我们使用了正常阅读语法的状态的两个属性。这没有特别的API。
现在请注意,我们使用两种不同的方式更新状态:
通过传递一个返回对象的函数。我们在handleClick函数中做了这个。
通过传递一个常规对象。我们在区间回调中做了这个。
这两种方式都是可以接受的,但是当你同时读写国家时,第一种是可取的(我们这样做)。在区间回调中,我们只写入状态而不读取它。如有疑问,请始终使用第一个函数作为参数的语法。竞争条件下更安全,因为setState实际上是一个异步方法。
我们如何更新状态?我们返回一个具有我们想要更新的新值的对象。请注意,在两次调用setState的过程中,我们只是从状态字段传递一个属性,而不是两个。这是完全没问题的,因为setState实际上将你传递它的东西(函数参数的返回值)与现有状态合并在一起。因此,在调用setState时不指定属性意味着我们不希望更改该属性(但不能删除它)。
准则 #8:React will react()
React命名的由来是因为它可以对状态的改变做出回应(不是及时响应的,而是按时间表同步的)。有个笑话说React 应该命名为Schedule。
然而,当任何组件的状态被更新时,我们用肉眼观察到的确实是对该更新的即时响应,并在浏览器DOM 中自动反映组件的更新(如果需要的话)。
将渲染函数的输入分为两种:
由父组件传递来的props:
可以被实时更新的内部私有状态:
当渲染函数的输入改变时,它的输出也可能改变。
React 保存了渲染的历史记录,当发现一个渲染与前一个不同时,React 会计算两个渲染之间的差异,并将其有效地转换为可以在DOM中执行的实际DOM操作。
基础 #9: React 是你的代理
你可以将React视为我们聘请的与浏览器通信的代理。以上面的当前时间戳显示为例。 我们不是手动进入浏览器并调用DOM API操作来每秒查找及更新p#timestamp元素,而是我们仅仅改变了组件状态的一个属性,React会代表我们完成了与浏览器通信的工作。我相信这就是React流行的真正原因。我们讨厌与浏览器先生(以及它所支持的DOM语言的许多方言)交谈,而React自愿为我们做了所有的沟通,而且是免费的!
基础#10: 每一个React组件都有一个故事(第二部分)
现在我们已经知道了一个组件的状态,以及为何当这个状态发生变化时会发生一些不可思议的事情了,让我们学习下关于这个过程的最后几个概念吧。
组件在以下情况下可能需要重新渲染,当其状态得到更新时,或者当父组件决定改变传递给组件的属性时
如果后者发生,React会调用另一个生命周期方法componentWillReceiveProps。
如果状态对象或传入的属性被改变,React就有重要的决定要做。应该在DOM中更新组件嘛?这就是为什么它在这里调用另一个重要的生命周期方法(shouldComponentUpdate)的原因了。这个方法是一个真正的问题所在,所以如果你需要自己定制或优化渲染过程,你必须通过返回true或false来回答这个问题。
如果没有指定自定义的shouldComponentUpdate,在大多数情况下,React默认的东西是足够的好。
首先,React在此处调用另一个生命周期方法componentWillUpdate。然后React将计算新的渲染输出并将其与上次的渲染输出进行比较。
如果渲染输出完全一样,React什么也不做(不需要和Browser沟通)。
如果存在差异,React就会像前文中看到的那样,将差异发给浏览器。
无论如何,由于更新过程已经发生(即使输出完全相同),React也会调用最终生命周期方法componentDidUpdate。
生命周期方法实际上是逃生舱。如果你没有做任何特殊的事情,你可以在没有它们的前提下创建完整的应用程序。他们非常方便于分析应用程序中发生的事情,并进一步优化React更新的性能。
就这些了。不管你信不信,上面你所学到的内容(或者其中的一部分),你都可以开始创建一些有趣的React应用程序了。如果你渴望学到更多,请查看下我在 Pluralsight上的React.js入门课程:React.js入门
Learn the basics of 学习React.js的基础知识,并从头构建一个浏览器内的、数学技能的儿童游戏。www.pluralsight.com
我也强烈推荐Alex和Eve编写的Learning React一书 。
本文最初发表在EdgeCoders上( 原文链接)。本文的EdgeCoders版本使用了交互式代码示例,其中你可以在文章内部编辑和重新运行该代码。
感谢您的阅读。如果你觉得本文对你有所帮助,请推荐和共享之。更多关于React.js和JavaScript的文章请关注我。
如您有何疑问,请联系小编:
15201480058
以上是关于猿技术React.js 基础概念一览的主要内容,如果未能解决你的问题,请参考以下文章