个性化阅读
专注于IT技术分析

React教程:如何入门及其比较(1)

本文概述

前端尤其是JavaScript是一个陌生的世界。每天都在大量推出的新事物经常被那些不与之合作的人和许多与之合作的人嘲笑。尽管如此, 有时我们还是对新的信息, 图书馆和讨论不知所措, 我们希望有一些稳定的东西, 例如可以在船上待更长久的避风港。最近, React似乎是动态JavaScript演化海洋中的这个温顺港口。

考虑到这一点, 我们决定制作此多部分的React教程, 以展示其功能, 并了解它与Angular和VueJS的比较。

React作为灯塔的插图清楚地显示在JavaScript代码的海洋上

当然, React并不是我们唯一可以使用的港口, 但是目前, 它是最受欢迎, 稳定和创新的解决方案之一, 尽管它仍然可以进行大量升级, 但它们比起改进的选择更多而不是功能的必要性。

2019年的React状态

React是一个视图库, 我们可以追溯到2011年, 当时它的第一个原型FaxXs出现在其Facebook页面上, React本身是由JSConfUS的Jordan Walke(也是上述原型的作者)介绍的。 2013年5月29日, 并于2013年7月2日在GitHub上公开可用。

2014年, 当会议开始出现以扩大社区并普及React时, React继续变得越来越受欢迎。但从我的角度来看, 2015年对于React来说是里程碑式的一年, 大型公司(例如Airbnb和Netflix)开始喜欢并采用React解决方案。另外, React Native也在那年出现。 React Native背后的想法并非绝对新颖, 但值得关注, 尤其是在Facebook支持下。

另一个重大变化是Flux实现Redux。这使状态管理方法更容易实现和更容易, 使之成为迄今为止最成功的实现。

从那时到现在, 还有许多其他可用的东西, 包括React工具, 重写的核心算法, Fiber, 语义版本更改等等。快进到今天, 我们是在16.6.3上, 大概是在带有Hooks的新版本发布之前的几个星期(本来应该是16.7.0, 但是由于对React.lazy的一些修复, 该版本已经发布)。 React众所周知且稳定, 并获得了很好的意见。

但是什么是React?

好吧, 如果你是前端开发人员并且还没有听说过, 那么我要说的是祝贺, 因为这是一项壮举。

除了笑话, React是基于声明式组件的视图库, 可帮助你构建UI。它是一个库, 而不是框架, 尽管起初许多人将其描述为后者。

显然, 如果我们要添加Redux, React Router等, 它将开始拥有所有必要的内容来制作常规的单页应用程序, 这可能是为什么有时将其误称为框架而不是库的原因。 。如果有的话, 可以说, 将环境的所有组件放在一起, 术语”框架”在某种程度上是合适的, 但是React本身只是一个库。

让我们从命名开始, 并专注于React的不同之处, 以及在它诞生之前我们没有的东西。首先, 当你第一次考虑React时, 你会想到JSX, 因为当你查看代码时, 它是第一眼。 JSX是一种JavaScript语法扩展, 在某种程度上类似于HTML / XML。在React和JSX方面, 我们与HTML有一些区别, 例如React中的类是className, 没有tabindex但只有tabIndex, 样式接受具有camelCased属性的JavaScript对象, 依此类推。

有一些细微的差异, 但是任何人都应该立即将它们拾起。事件处理是通过例如onChange和onClick属性进行的, 这些属性可用于附加某些函数来处理事件。另外, 以后的组件可以通过使用props自由地重用和定制, 因此没有理由多次编写完全相同的代码。

import React, { Component } from 'react';

export default class App extends Component {
    render() {
        return (
            <div>Hello World, {this.props.name}</div>
        );
    }
}

但是, 实际上, JSX在React中并不是绝对必要的。你可以编写常规函数来创建元素, 而无需使用JSX。上面的相同代码可以像下面一样使用。

import React, { Component } from 'react';

export default class App extends Component {
    render() {
        return React.createElement(
            'div', null, 'Hello World, ', this.props.name
        );
    }
}

显然, 我不建议你使用这种语法, 尽管在某些情况下它可能会派上用场(例如, 你想引入一个很小的东西而又不想更改构建环境)。

实际上, 我有另一个原因要显示上面的代码段。通常, 开发人员不理解为什么我们需要执行以下操作:

import React from 'react';

该片段应具有自我解释性。即使我们正在提取Component, 我们仍然需要React, 因为Babel将JSX之上的代码转换为React.createElement之下的代码。因此, 如果我们不导入React, 它将对我们来说简直就是失败。我提到了Babel, 这是一个工具, 可以帮助我们介绍JavaScript中尚未使用的内容(或在浏览器中)或对其进行某种扩展的内容(或Babel 7支持的不同语言, 如TypeScript)。感谢Babel:

  • JSX将变成浏览器可以理解的功能。
  • 我们可以使用浏览器尚不具备的新功能(例如, 类属性)。
  • 我们可以添加较新的浏览器中的功能, 而较旧的浏览器中不存在的功能, 同时保持较旧的浏览器支持。

简而言之, 明天就是今天的JavaScript。这可能是需要自己撰写文章的内容。值得一提的是, React导入还可以通过其他一些技术来绕过(例如通过Webpack引入ProvidePlugin等), 但是由于此处空间有限, 我们将避免使用它, 并假设用户将使用Create React App( CRA)(有关此工具的更多信息将在后面提及)。

第二个要点是, React基于虚拟DOM, 这比JSX本身重要得多。简而言之, 虚拟DOM是由开发人员编写的JavaScript表示的理想树的内存, 稍后将其与真实DOM进行比较, 并在称为对帐的过程中将其同步。

React与Angular和Vue相比如何?

我非常不喜欢比较库, 尤其是当我们被迫将梨与苹果(库与框架等)进行比较时。

因此, 我将尝试使用一系列与技术问题无关的简短问题和答案来将React与Angular和Vue进行比较, 而不是说” X比Y更好, 因为它使用了JSX而不是模板, 因此比不上Y。 “诸如此类的要点通常是个人喜好, 是一个人的主观选择。在React及其所有主要竞争对手(想到的是Angular和Vue)中, 速度, 内存分配等也非常相似。关于此事, 有一个非常好的报告, 但是请记住这一点:绝大多数应用程序看起来并不像真正的大表, 它们可以交换10k表中的行。因此, 这些结果也是纯速度实验。在现实世界中, 你一开始就不会做这种事情。

React vs. Angular vs. Vue.js的插图

因此, 让我们看一下与React相关的一些问题以及它与竞争对手的比较:

我想有很多工作机会。 React有多流行?

好吧, 这很容易回答-选择React。实际上, 我想说React的职位空缺大约是Vue的6到10倍(相当大的差距, 但有些门户网站是1:50, 有些门户是1:6), 比Vue多得多, 而2-4倍。比Angular。对React专家的需求很旺盛, 那么为什么Vue在GitHub上如此受欢迎(事实上, 它比React拥有更多的明星)却职位空缺更少?我不知道。

我想要一个大社区, 大量图书馆, 快速解决可能出现的问题的解决方案。

React别再看了。

它易于使用并且使开发愉快吗?

根据JS州2018年和2017年的报告, React和Vue再次享有很高的声誉, 大多数开发人员表示将再次使用它们。另一方面, Angular有逐年趋势, 使越来越多的人说他们不会再使用它了。

我想创建一个新的单页应用程序, 但是我不想搜索库。

我可能会说, 那是唯一可以选择Angular更好的选择。

没有大公司。我想尽可能独立, 该选择哪一个?

Vue-它是我们三人组合中唯一的独立人。 (Facebook支持React, 而Google支持Angular。)

最简单的开始和最快的学习曲线?

Vue /React。我在这里倾向于Vue, 但这只是我个人的看法。

为什么?因为你甚至不需要了解JSX(它是可选的), 并且它基本上只是HTML + CSS + JavaScript。

React教程:第一个应用程序入门

React教程:创建React应用程序成功消息的屏幕截图

如今, 从React开始最简单的方法是使用CRA, 这是一个CLI工具, 可为你创建一个项目, 并帮助你避免Webpack / Babel等的所有必要设置。取而代之的是, 你要依赖默认配置的方式以及一段时间后配置的内容。因此, 你无需关心某些关键库的主要更新。

当然, 稍后, 你可以运行npm run exit来”弹出”自己并自己处理每个方面。这种方法有其自身的长处, 因为你可以使用本来无法使用的东西(例如, 装饰器)来增强你的应用程序, 但由于需要大量额外的文件和更多的时间, 因此也可能令人头疼。

因此, 要做的第一件事是:

npx create-react-app {app-name}

然后npm run start, 你就可以开始了。

类与功能组件

我们应该首先解释这些组件之间的差异。基本上, 每个组件都可以是一个函数或类。它们之间的主要区别在于, 第一类具有一些功能组件中不可用的功能:它们可以具有状态并使用引用, 生命周期等。这是当前的运行状态, 并且从16.7版开始(或者它将由于已经提到的更改而被调用), 我们也会有钩子, 因此使用钩子可以实现状态和引用。

类组件有两种类型:Component和PureComponent。两者之间的唯一区别是PureComponent在进行道具和状态的浅层比较-在你不想制作”浪费的”渲染的情况下, 它具有自己的好处, 即组件及其子级处于完全相同的状态渲染后。不过, 这只是一个比较浅的比较。如果你想实现自己的比较(例如, 因为要传递复杂的道具), 则只需使用Component并覆盖shouldComponentUpdate(默认情况下会返回true)。从16.6开始, 函数组件也提供了类似的功能-由于React.memo是一个高阶组件, 默认情况下的行为类似于PureComponent(浅比较), 但是它需要第二个参数, 你可以在其中传递自己的自定义道具比较。

通常, 如果可以使用功能组件(不需要类功能), 则可以使用它。从16.7.0开始, 很快就会由于生命周期方法而要求使用类组件。我倾向于认为功能组件更透明, 更易于推理和理解。

React生命周期方法

安装,更新和卸载组件的图示

构造函数(道具)

  • 可选, 尤其是在CRA如此流行的情况下, 默认情况下包括JavaScript的类字段声明。声明是否要通过箭头函数在类主体中绑定方法毫无意义。类似的状态也可以初始化为类属性。
  • 仅应用于初始化ES6类中的对象和绑定方法的局部状态。

componentDidMount()

  • 在此处拨打Ajax电话。
  • 如果你需要事件监听器, 订阅等, 请在此处添加它们。
  • 你可以在此处使用setState(但它将使组件重新呈现)。

componentWillUnmount()

  • 清除所有仍在进行的内容-例如, 应该中断Ajax, 取消订阅, 清除计时器等。
  • 不要调用setState, 因为它将毫无意义, 因为该组件将被卸载(并且你将收到警告)。

componentDidUpdate(prevProps, prevState, 快照)

  • 在组件刚刚完成更新时发生(在初始渲染时不发生)。
  • 具有三个可选使用的参数(先前的道具, 先前的状态以及仅当你的组件实现getSnapshotBeforeUpdate时才会显示的快照)。
  • 仅当shouldComponentUpdate返回true时才会发生。
  • 如果在此处使用setState, 则应加以保护, 否则将陷入无限循环。

shouldComponentUpdate(nextProps, nextState)

  • 仅用于性能优化。
  • 如果返回false, 则不会调用渲染。
  • 如果覆盖的SCO只是简短的道具/状态比较, 则可以使用PureComponent代替。

getSnapshotBeforeUpdate()

  • 可用于保留有关当前DOM的某些信息, 例如当前滚动位置, 以后可在componentDidUpdate中重用以恢复滚动位置。

componentDidCatch(错误, 信息)

  • 应该发生记录错误的地方。
  • 可以调用setState, 但是在将来的版本中, 它将被静态方法getDerivedStateFromError(error)取代, 该方法将通过返回值来更新状态来更新状态。

有两种额外的方法, 它们都是静态的, 并在其他说明中提到

静态getDerivedStateFromError(错误)

  • 错误信息在这里可用。
  • 应该返回一个对象值, 该值将更新可用于处理错误的状态(通过显示某些内容)。
  • 由于它是静态的, 因此无法访问组件实例本身。

静态getSnapshotBeforeUpdate(props, state)

  • 应该在道具随时间变化的情况下使用-例如, 根据React docs的说明, 它可能对过渡组件很有用。
  • 由于它是静态的, 因此无法访问组件实例本身。

请注意, 截至目前为止, 几乎没有其他可用的方法, 但是应该在React 17.0中将其删除, 因此, 这里未提及它们。

状态与道具

让我们从道具开始, 因为它们更易于解释。道具是传递给组件的属性, 以后可在组件中重用以显示信息/业务逻辑等。

import React, { Component } from 'react';

export default class App extends Component {
   render() {

       return (
           <div>
               <HelloWorld name="Someone :)"/>
           </div>
       );
   }
}

const HelloWorld = (props) => <div>Hello {props.name}</div>

在上面的示例中, 名称是道具。道具是只读元素, 不能在子组件中直接更改。而且, 人们经常会犯下一种不良习惯, 那就是将道具复制到州, 然后在州内进行操作。当然, 在某些情况下, 你可能想要执行”在提交后会更新父组件的初始状态”之类的事情, 但是这种情况更为罕见-在这种情况下, 初始状态供给可能有意义。另外, 不仅可以将诸如字符串之类的属性传递给子组件, 还可以将数字, 对象, 函数等传递给子组件。

道具还有一个更有用的东西, 称为defaultProps, 它是一个静态字段, 它可以告诉你组件的默认道具是什么(例如, 当它们不传递给组件时)。

在”提升状态”的情况下, 一个组件(父组件)的状态随后被其子组件重用(例如, 一个子组件显示它, 另一个子组件允许编辑), 那么我们需要将该函数从父级, 这使我们可以更新父级的本地状态。

另一方面, 状态是可以修改的局部状态, 但可以使用this.setState间接进行修改。如果有人直接更改状态, 则组件将不会意识到该更改, 也不会重新呈现该更改以反映所提及的状态更改。

SetState是一种更改本地状态对象的方法(通过执行浅合并), 然后, 该组件通过重新呈现自身来进行响应。请注意, 在使用setState之后, this.state属性不会立即反映函数中提到的更改(它具有异步特性), 因为一些setState实例可能由于优化而被批处理在一起。在以下几种可能性之一中, 有几种方法可以使我们在更新状态后立即对组件进行操作:

  • setState({value:’5′})
  • setState((state, props)=>({value:state.name +”’s”}))
  • setState([上面的对象/函数], ()=> {})–这种形式允许我们附加回调, 当状态反映我们想要的数据时(在第一个参数中), 将调用该回调。
import React, { Component } from 'react';

export default class App extends Component {
   state = {
       name: 'Someone :)'
   }

   onClick = () => this.setState({ name: 'You' })

   render() {
       return (
           <div>
               <HelloWorld name={this.state.name} onClick={this.onClick}/>
           </div>
       );
   }
}

const HelloWorld = (props) => <div onClick={props.onClick}>Hello {props.name}</div>

React上下文

React最近稳定了Context API(虽然已经在React中使用了很长时间, 但尽管已被Redux等最流行的库广泛使用, 但仍是一项实验性功能), 它可以帮助我们解决一个问题:道具钻探。简短地进行道具钻探是在结构中深入传递道具的一种方法, 例如, 它可以是组件的某种主题, 特定语言的本地化, 用户信息等等。在Context之前(或者更确切地说, 在成为非实验对象之前), 通过从父级到子级递归地传递到最后一片叶子来进行深入挖掘(显然, Redux也可以解决该问题)。请注意, 此功能只能解决支柱钻探问题, 不能替代Redux或Mobx。显然, 如果你仅为此使用状态管理库, 则可以自由替换它。

本文总结

至此, 我们的React教程的第一部分结束了。在接下来的文章中, 我们希望解决更多高级主题, 从样式和检查类型到生产部署和性能优化。

相关:维护控制权:Pt Webpack and React指南。 1个

赞(0)
未经允许不得转载:srcmini » React教程:如何入门及其比较(1)

评论 抢沙发

评论前必须登录!