React 教程:快速上手指南

翻译:疯狂的技术宅
原文: https://www.toptal.com/react/...

本文首发微信公众号:jingchengyideng
欢迎关注,天天都给你推送新鲜的前端技术文章html


前端和 JavaScript 是一个奇怪的世界。大量不断推出的新技术的同时,也在被不须要它们的人嘲笑,每每不少人都会这样作。咱们有时会对不断涌现的信息、库和讨论感到不知所措,总但愿能有一些稳定的东西,就像能让咱们能够休整一段时间的避风港。最近 React 彷佛有变成 JavaScript 演变海洋中温暖港湾的趋势。前端

正是考虑到这一点,咱们决定制做这个 React 系列教程,展现它的功能,并看看它与 Angular 和 VueJS 相比有什么特色。vue

React 是一座耸立在 JavaScript 代码海上醒目的灯塔

固然 React 并非惟一的选择,但目前它是最受欢迎、最稳定、最具备创新性的解决方案之一,虽然它仍然在不断升级,但更多的是在改进,而不是增长功能。react

2019年的 React

React 是一个视图库,能够一直追溯到2011年,当时它的第一个原型名为 FaxJs,并出如今 Facebook 上,React 是由 Jordan Walke(他也是上述原型的做者)于2013年5月29日在 JSConfUS 推出的,并于2013年7月2日在 GitHub 上公开发布。git

在2014年,当开始扩大社区并推广 React 时,它受到持续欢迎。然而从个人角度来看,2015年是大型公司(例如 Airbnb 和 Netflix )开始喜欢并采用 React 的里程碑年。此外,当年还出现了React Native。 React Native背后的想法并非什么全新的东西,不过看起来颇有趣,尤为是由于它获得了 Facebook 的支持。程序员

另外一个重大变化是 Redux,一个 Flux 实现。这使状态管理方式更加简单友好,使其成为迄今为止最成功的实现。github

从其出现一直到如今,还有不少其余的东西供咱们使用,包括 React tools,重写了核心算法;Fiber 用于语义转换版本控制等等。到了今天,咱们处于 v16.6.3,几周后可能就会发布支持 Hooks 的新版本(它应该在 16.7.0 获得支持,但因为对 React.lazy 作了一些修复,就先发布了一个版本)。React 因为其名气和稳定性得到了普遍好评。面试

但 React 究竟是什么?

好吧,若是你身为前端开发人员可是历来都没有据说过,那么我就要说声“恭喜你”,由于这是一个了不得的壮举。算法

开个玩笑而已。React 是一个声明式的基于组件的视图库,能够帮助你构建 UI。它是一个库而不是一个框架,虽然最初不少人把它描述为后者。npm

显然,若是咱们要把 Redux 和 React Router 等添加到 React,它就拥有了制做常规单页应用程序所需的全部东西,这可能这就是它有时被错误地描述为框架而不是库的缘由 。若是必定要这样认为的话,将该环境的全部组件放在一块儿,术语“框架”可能有点适合它,但就其自己而言,React 仅仅是一个库。

不要再纠结改怎么对其分类了,先关注 React 有什么独特之处,一些以前没有注意到的东西。首先,当你第一次看到 React 时,就会想到 JSX,由于这是你看到代码时的第一个感觉。 JSX是一种 JavaScript 语法扩展,有点相似于 HTML/XML。说到 React 和 JSX,它们与 HTML 有一些区别,例如,React 中的类是 className,没有tabindex 可是有 tabIndex,样式接受具备驼峰命名的属性的 JavaScript 对象,依此类推。

有一些细微的差异,可是任何人都应该当即接受它们。事件处理是经过例如 onChangeonClick 属性实现的,这些属性能够用来附加一些函数来处理事件。此外,之后的组件能够经过使用 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 中(更确切地说是在浏览器中)支持的东西,或者以某种方式对 JavaScript 进行扩展(或者相似于 TypeScript,Babel 从 Babel 7 开始支持的不一样语言)。感谢Babel:

  • JSX 将被转化为成浏览器能够理解的代码。

    • 咱们可使用还没有在浏览器中实现的新功能(例如类属性)。
    • 咱们能够支持新浏览器中的特性,同时在旧浏览器中支持较旧的功能。

简而言之,在 JavaScript 中,就是今天的代码明天仍然能用;这可能须要为此专门再写一篇文章。值得一提的是,React 的导入也能够被一些其余技术绕过(好比经过 Webpack 引入 ProvidePlugin 等),可是因为篇幅有限,咱们将避免使用这种方式,并假设用户将使用 Create React App( CRA)(稍后将提到有关此工具的更多信息)。

另外一点比 JSX 自己更重要,那就是 React 基于虚拟 DOM。简而言之,虚拟 DOM 是用 JavaScript 编写的在内存中的理想树结构,稍后咱们会把它与真实 DOM 进行比较。

怎样与 Angular 和 Vue 进行比较?

我很不喜欢对库进行比较,特别是当咱们被迫把梨和苹果放在一块儿进行比较时。

所以,我将尝试使用一系列简短的问题和答案将 React 与 AngularVue 进行比较。这种比较与技术相关,而不是主观的做出 “X比Y更好,由于它使用 JSX 而不是模板。” 这种出于我的偏好的对比。另外在速度和内存分配等方面 React 与其主要竞争对手(Angular 和 Vue 都能想获得)很是类似,有一篇关于这个问题的文章很不错,但请记住这一点:绝大多数程序并不会作这种处理上万行数据的事。所以,这些结果也是纯粹的速度实验。实际上你也不会把这放在首位。

React vs. Angular vs. Vue.js

那么让咱们来看看关于 React 的问题以及它与竞争对手的比较:

我想拥有更多的工做机会。 React 到底有多受欢迎?

嗯,这很容易回答 —— 选择 React。实际上,我会说 React 的工做机会大约其它的 6 到 10 (可能出入比较大,在一些大网站是 50 倍,也有些网站是 6 倍),是 Vue 的 2 到 4倍,比 Angular 更多。对 React experts 的需求很大,可是为何 Vue 在 GitHub 上很是受欢迎(实际上它得到了比 React 更多的star)却没有更多的职位空缺?这点我不知道。【译者注:做者是美国人,这里指的是美国的就业市场】

我想要一个很大的社区,还有大量的库,可以快速解决可能出现的问题。
选 React,不要再犹豫了。

它是否容易使用,开发过程是否使人愉快?

2018年和2017年的 JS 状态报告显示,React 和 Vue 都享有良好的声誉,大多数开发人员表示会再次使用。另外一方面Angular 有一种趋势,每一年都会有愈来愈多的人说不会再次使用它。

我想建立一个新的单面应用,但我不想额外去找这种支持库。

我认为这大概是 Angular 值得选择的惟一缘由。

我不是大公司。可是但愿尽量独立,应该选择哪一个?

Vue —— 它是咱们三巨头中惟一独立的一个。 ( Facebook 支持 React,而 Google 支持 Angular。)

上手最简单和最快的学习曲线?

Vue/React。在这里我更倾向于 Vue,但这只是我我的的意见。至于为何?由于你不须要懂 JSX(它是可选的),它基本上只是 HTML + CSS + JavaScript。

React Tutorial:开始你的第一个程序

React tutorial:成功建立 React 应用后的屏幕截图

目前上手 React 最简单方法是使用 CRA,这是一个为你建立项目的 CLI 工具,可帮助你避免配置 Webpack / Babel 等环境。你只须要依赖默的认配置方式,并随着时间的推移更新包含在内的内容。多亏了这一点,你无需关心某些关键库的主要更新。

固然,稍后,你能够经过运行 npm run eject 来“弹出”本身并本身处理每一个细节。这种方法有其自身的优势,由于你能够增长原来不可用的东西(例如装饰器)来加强你的应用,但它也多是使人头疼的问题,由于它须要花费更多的时间去配置许多额外的文件。

因此,首先要作的是:

npx create-react-app {app-name}

而后 npm run start 就完成了。

类组件与函数组件

咱们应该先解释这些组件的不一样之处。基本上每一个组件能够是 functionclass。它们之间的主要区别在于,类组件有函数组件中没有的一些功能:它们有 state 并使用 refs、生命周期等。从 v16.7 开始咱们可使用 hooks,所以可使用 hooks 来进行 state 和 refs。

类组件有两种类型:ComponentPureComponent。它们惟一的区别是 PureComponent 能够对 props 和 state 进行浅层比较 —— 这在你不想“浪费”渲染资源的状况下有独到的好处,一个组件及其子组件刚好在渲染后处于相同状态。不过它只有一个浅层比较;若是你想实现本身的比较操做(假如你传递的是复杂的 props),只须要用 Component 并覆盖 shouldComponentUpdate(默认状况下返回true)。从 16.6 + 开始,在函数组件中也能够用相似的东西 —— 全靠 React.memo 这个更高阶的组件,在默认状况下表现得像 PureComponent(浅层比较),在你进行自定义的 props 比较时它还须要第二个参数。

通常来讲若是你能用函数组件(假设你不须要类功能)那么就用它。不过从 16.7.0 开始,因为生命周期方法,只能用类组件。可是我认为函数组件更透明,更容易推理和理解。

React 生命周期方法

安装、更新和卸载组件

Constructor(props)

  • 可选,CRA 使其变得受欢迎,默认包含 JavaScript 的类字段声明。声明是否经过类中的箭头函数去绑定方法是没有意义的。相似的状态也能够初始化为类属性。

    • 仅用于 ES6 类中初始化对象的本地状态和绑定方法。

componentDidMount()

  • 在这里进行 Ajax 调用。
  • 若是你须要事件监听器,订阅等功能,能够在此处添加。
  • 你能够在这里使用 setState(可是它会使组件从新渲染)。

componentWillUnmount()

  • 清除全部仍在进行的东西 —— 例如,Ajax应该被中断,取消订阅,清除定时器等等。
  • 不要调用 setState,由于它没有意义,由于组件将会被卸载(而且你会获得一个警告)。

componentDidUpdate(prevProps, prevState, snapshot)

  • 在组件刚刚更新完毕时执行(在开始渲染时不会)。
  • 有三个可选的参数(之前的props,之前的 state 和只有在你的组件实现 getSnapshotBeforeUpdate 时才会出现的快照 )。
  • 仅当 shouldComponentUpdate 返回true时才会执行。
  • If you use setState here, you should guard it or you will land in an infinite loop.

    • 若是你在这里用到了 setState,应该保护它,不然将会陷入无限循环。

shouldComponentUpdate(nextProps, nextState)

  • 仅用于性能优化。
  • 若是返回 false,则不会调用渲染器。

    • 若是重写的 SCO 只是对 props/state的浅层比较,可使用 PureComponent

getSnapshotBeforeUpdate()

  • 可用于保存一些与当前 DOM 有关的信息,例如当前的滚动位置,稍后可在 componentDidUpdate 中重用,用来恢复滚动的位置。

componentDidCatch(error, info)

  • 应该记录日志错误的地方。
  • 能够调用 setState,但在之后的版本中,将会在静态方法getDerivedStateFromError(error) 中被删除,它将经过返回一个值来更新状态。

还有两种静态方法,在其余的段落中提到过

static getDerivedStateFromError(error)

    • 此处提供错误信息。
    • 应返回一个对象值,该值将会更新可用于处理错误的状态(经过显示内容)。
    • 因为它是静态的,所以没法访问组件实例自己。

    static getSnapshotBeforeUpdate(props, state)

    • 应该在 props 随时间变化的状况下使用 —— 例如根据 React docs,它可能用于转换组件。
    • 因为它是静态的,所以没法访问组件实例自己。

    注意,目前还有更多可用的方法,但它们可能会在 React 17.0 中被删除,因此就不在这里没有提起了。

    State vs. Props

    咱们先从 Props 开始,由于它更容易解释。Props 是传给组件的属性,之后能够在组件显示信息或业务逻辑时重用它 。

    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>

    在上面的例子中,name 是一个 prop。prop 是只读元素,不能直接在子组件中更改。不少人有一种不太好的习惯,那就是把 prop 复制到 state ,而后再对 state 进行操做。固然有时候你但愿执行相似 “在提交以后去更新父组件的初始状态” 这样的操做,但这种状况很是少见 —— 在这种状况下,更新初始状态可能有意义。另外不只能够给子组件传递字符串这样的 prop ,还能够传递数字、对象、函数等。

    prop 还有一个更有用的东西叫作 defaultProps,这是一个静态字段,它能够告诉你组件的默认 prop 是什么(好比当它们没有传递给组件时)。

    在“状态提高”的状况下,其中一个组件(父组件)具备稍后由其子组件重用的状态(例如,一个子组件用来显示而另外一个用来编辑),那么咱们须要将该功能从父组件传递给子组件。 它容许咱们更新父级的本地状态。
    另外一方面,状态是一个能够修改的本地状态,可是经过 this.setState 间接修改。若是直接去改变状态,组件将不会感知到,更不会由于状态的改变而从新渲染。

    SetState 是一种更改本地状态对象的方法(经过执行浅层合并),以后组件经过从新渲染本身来响应它。请注意,在使用 setState 以后,this.state 属性不会当即对更改(它具备异步性质)做出反应,由于优化的缘由,可能会将 setState 的几个实例一块儿进行批处理。调用它的方式有好几种,其中一种方式容许咱们在对状态进行更新可以后当即对组件执行某些操做:

    • setState({value: ‘5’})

      • setState((state, props) => ({value: state.name + “‘s”}))
    • setState([object / function like above], () => {}) —— 这个表单容许咱们附加 callback,当 state 显示咱们想要的数据时被调用(在第一个参数)。
    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 Context

    React 最近稳定的 Context API(已经在 React 中存在了至关长的时间,尽管被 Redux 等一些最受欢迎的库普遍使用,倒是一个实验性功能)有助于咱们解决一个问题:Props drilling。简而言之 Props drilling 是在结构中深刻传递 props 的一种方式 —— 例如,它能够是组件的某种主题、针对特定语言的本地化、用户信息等。在 Context出现以前(或者更确切地说,在它变成非实验功能以前),它是经过递归方式从父级一直传递到到子级的最后一级的来进行钻取的(显然还有能够解决这个问题的 Redux)。请注意,此功能仅仅用于解决 Props drilling 的问题,而且不能替代 Redux 或 Mobx 等。固然若是你只使用状态管理库,则能够随意替把它替换掉。

    总结

    这是咱们的React教程的第一部分。在后续的文章中,咱们会设计更多高级主题,包括样式和类型检查,以及生产部署和性能优化。


    欢迎继续阅读本专栏其它高赞文章:


    本文首发微信公众号:jingchengyideng

    欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

    欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章