当前位置: 首页 / 技术干货 / 正文
好程序员web前端培训分享React学习笔记(一)

2020-04-26

好程序员 web前端培训

  好程序员web前端培训分享React学习笔记(一)React的起源和发展React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。

React与传统MVC的关系

轻量级的视图层A JavaScript library for building user interfaces

React不是一个完整的MVC框架,多可以认为是MVC中的V(View),甚至React并不非常认可MVC开发模式;React 构建页面 UI 的库。可以简单地理解为,React 将将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,就成了我们的页面。

React高性能的体现:虚拟DOM

React高性能的原理:

Web开发中我们总需要将变化的数据实时反应到UI上,这时就需要对DOM进行操作。而复杂或频繁的DOM操作通常是性能瓶颈产生的原因(如何进行高性能的复杂DOM操作通常是衡量一个前端开发人员技能的重要指标)。

React为此引入了虚拟DOM(Virtual DOM)的机制:在浏览器端用Javascript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM新。而且React能够批处理虚拟DOM的刷新,在一个事件循环(Event Loop)内的两次数据变化会被合并,例如你连续的先将节点内容从A-B,B-A,React会认为A变成B,然后又从B变成A UI不发生任何变化,而如果通过手动控制,这种逻辑通常是极其复杂的。

尽管每一次都需要构造完整的虚拟DOM树,但是因为虚拟DOM是内存数据,性能是极高的,部而对实际DOM进行操作的仅仅是Diff分,因而能达到提高性能的目的。这样,在性能的同时,开发者将不再需要关注某个数据的变化如何新到一个或多个具体的DOM元素,而只需要关心在任意一个数据状态下,整个界面是如何Render的。

React Fiber:

react 16之后发布的一种react 核心算法,React Fiber是对核心算法的一次重新实现(官网说法)。之前用的是diff算法。

在之前React中,新过程是同步的,这可能会导致性能问题。

React决定要加载或者新组件树时,会做很多事,比如调用各个组件的生命周期函数,计算和比对Virtual DOM,后新DOM树,这整个过程是同步进行的,也就是说只要一个加载或者新过程开始,中途不会中断。因为JavaScript单线程的特点,如果组件树很大的时候,每个同步任务耗时太长,就会出现卡顿。

React Fiber的方法其实很简单——分片。把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。

React的特点和优势

1、虚拟DOM

我们以前操作dom的方式是通过document.getElementById()的方式,这样的过程实际上是先去读取html的dom结构,将结构转换成变量,再进行操作

reactjs定义了一套变量形式的dom模型,一切操作和换算直接在变量中,这样减少了操作真实dom,性能真实相当的高,和主流MVC框架有本质的区别,并不和dom打交道

2、组件系统

react核心的思想是将页面中任何一个区域或者元素都可以看做一个组件 component

那么什么是组件呢?

组件指的就是同时包含了html、css、js、image元素的聚合体

使用react开发的核心就是将页面拆分成若干个组件,并且react一个组件中同时耦合了css、js、image,这种模式整个颠覆了过去的传统的方式

3、单向数据流

其实reactjs的核心内容就是数据绑定,所谓数据绑定指的是只要将一些服务端的数据和前端页面绑定好,开发者只关注实现业务就行了

4、JSX 语法

vue中,我们使用render函数来构建组件的dom结构性能较高,因为省去了查找和编译模板的过程,但是在render中利用createElement创建结构的时候代码可读性较低,较为复杂,此时可以利用jsx语法来在render中创建dom,解决这个问题,但是前提是需要使用工具来编译jsx

 

编写个react应用程序

react开发需要引入多个依赖文件:react.js、react-dom.js,分别又有开发版本和生产版本,create-react-app里已经帮我们把这些东西都安装好了。把通过CRA创建的工程目录下的src目录清空,然后在里面重新创建一个index.js. 写入以下代码:

// 从 react 的包当中引入了 React。只要你要写 React.js 组件就必须引入React, 因为react里有一种语法叫JSX,稍后会讲到JSX,要写JSX,就必须引入Reactimport React from 'react'// ReactDOM 可以帮助我们把 React 组件渲染到页面上去,没有其它的作用了。它是从 react-dom 中引入的,而不是从 react 引入。import ReactDOM from 'react-dom'// ReactDOM里有一个render方法,功能就是把组件渲染并且构造 DOM 树,然后插入到页面上某个特定的元素上ReactDOM.render(// 这里就比较奇怪了,它并不是一个字符串,看起来像是纯 HTML 代码写在 JavaScript 代码里面。语法错误吗?这并不是合法的 JavaScript 代码, “在 JavaScript 写的标签的”语法叫 JSX- JavaScript XML。  <h1>欢迎进入React的世界</h1>,// 渲染到哪里  document.getElementById('root'))

元素与组件

如果代码多了之后,不可能一直在render方法里写,所以就需要把里面的代码提出来,定义一个变量,像这样:

import React from 'react'import ReactDOM from 'react-dom'// 这里感觉又不习惯了?这是在用JSX定义一下react元素const app = <h1>欢迎进入React的世界</h1>ReactDOM.render(

  app,

  document.getElementById('root'))

函数式组件

由于元素没有办法传递参数,所以我们就需要把之前定义的变量改为一个方法,让这个方法去return一个元素:

import React from 'react'import ReactDOM from 'react-dom'// 特别注意这里的写法,如果要在JSX里写js表达式(只能是表达式,不能流程控制),就需要加 {},包括注释也是一样,并且可以多层嵌套const app = (props) => <h1>欢迎进入{props.name}的世界</h1>ReactDOM.render(

  app({

    name: 'react'

  }),

  document.getElementById('root'))

这里我们定义的方法实际上也是react定义组件的种方式-定义函数式组件,这也是无状态组件。但是这种写法不符合react的jsx的风格,好的方式是使用以下方式进行改造

import React from 'react'import ReactDOM from 'react-dom'const App = (props) => <h1>欢迎进入{props.name}的世界</h1>ReactDOM.render(

  // React组件的调用方式  <App name="react" />,

  document.getElementById('root'))

这样一个完整的函数式组件就定义好了。但要注意!注意!注意!组件名必须大写,否则报错。

class组件

ES6的加入让JavaScript直接支持使用class来定义一个类,react的第二种创建组件的方式就是使用的类的继承,ES6 class是目前官方推荐的使用方式,它使用了ES6标准语法来构建,看以下代码:

import React from 'react'import ReactDOM from 'react-dom'class App extends React.Component {

  render () {

    return (

      // 注意这里得用this.props.name, 必须用this.props      <h1>欢迎进入{this.props.name}的世界</h1>

    )

  }}ReactDOM.render(

  <App name="react" />,

  document.getElementById('root'))

运行结果和之前完全一样,因为JS里没有真正的class,这个class只是一个语法糖, 但二者的运行机制底层运行机制不一样。

  • 函数式组件是直接调用, 在前面的代码里已经有看到
  • es6 class组件其实就是一个构造器,每次使用组件都相当于在实例化组件,像这样:

import React from 'react'import ReactDOM from 'react-dom'class App extends React.Component {

 render () {

 return (

   <h1>欢迎进入{this.props.name}的世界</h1>

  )

  }}const app = new App({

 name: 'react'}).render()ReactDOM.render(

 app,

 document.getElementById('root'))

老的一种方法

16以前的版本还支持这样创建组件, 但现在的项目基本上不用

React.createClass({

  render () {

    return (

      <div>{this.props.xxx}</div>

    )

  }})

组件的组合、嵌套

将一个组件渲染到某一个节点里的时候,会将这个节点里原有内容覆盖

组件嵌套的方式就是将子组件写入到父组件的模板中去,且react没有Vue中的内容分发机制(slot),所以我们在一个组件的模板中只能看到父子关系

// 从 react 的包当中引入了 React 和 React.js 的组件父类 Component// 还引入了一个React.js里的一种特殊的组件 Fragmentimport React, { Component, Fragment } from 'react'import ReactDOM from 'react-dom'class Title extends Component {

  render () {

    return (

      <h1>欢迎进入React的世界</h1>

    )

  }}class Content extends Component {

  render () {

    return (

      <p>React.js是一个构建UI的库</p>

    )

  }}/** 由于每个React组件只能有一个根节点,所以要渲染多个组件的时候,需要在外层包一个容器,如果使用div, 会生成多余的一层domclass App extends Component {  render () {    return (        <div>            <Title />        <Content />      </div>    )  }}**/// 如果不想生成多余的一层dom可以使用React提供的Fragment组件在外层进行包裹class App extends Component {

  render () {

    return (

      <Fragment>

        <Title />

        <Content />

      </Fragment>

    )

  }}ReactDOM.render(

  <App/>,

  document.getElementById('root'))

#JSX 原理

要明白JSX的原理,需要先明白如何用 JavaScript 对象来表现一个 DOM 元素的结构?

看下面的DOM结构

<div class='app' id='appRoot'>

  <h1 class='title'>欢迎进入React的世界</h1>

  <p>

    React.js 是一个帮助你构建页面 UI 的库

  </p></div>

上面这个 HTML 所有的信息我们都可以用 JavaScript 对象来表示:

{

  tag: 'div',

  attrs: { className: 'app', id: 'appRoot'},

  children: [

    {

      tag: 'h1',

      attrs: { className: 'title' },

      children: ['欢迎进入React的世界']

    },

    {

      tag: 'p',

      attrs: null,

      children: ['React.js 是一个构建页面 UI 的库']

    }

  ]}

但是用 JavaScript 写起来太长了,结构看起来又不清晰,用 HTML 的方式写起来就方便很多了。

于是 React.js 就把 JavaScript 的语法扩展了一下,让 JavaScript 语言能够支持这种直接在 JavaScript 代码里面编写类似 HTML 标签结构的语法,这样写起来就方便很多了。编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构。

下面代码:

import React from 'react'import ReactDOM from 'react-dom'class App extends React.Component {

  render () {

    return (

      <div className='app' id='appRoot'>

        <h1 className='title'>欢迎进入React的世界</h1>

        <p>

          React.js 是一个构建页面 UI 的库

        </p>

      </div>

    )

  }}ReactDOM.render(

    <App />,

  document.getElementById('root'))

编译之后将得到这样的代码:

import React from 'react'import ReactDOM from 'react-dom'class App extends React.Component {

  render () {

    return (

      React.createElement(

        "div",

        {

          className: 'app',

          id: 'appRoot'

        },

        React.createElement(

          "h1",

          { className: 'title' },

          "欢迎进入React的世界"

        ),

        React.createElement(

          "p",

          null,

          "React.js 是一个构建页面 UI 的库"

        )

      )

    )

  }}ReactDOM.render(

    React.createElement(App),

  document.getElementById('root'))

React.createElement 会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等, 语法为

React.createElement(

  type,

  [props],

  [...children])

所谓的 JSX 其实就是 JavaScript 对象,所以使用 React 和 JSX 的时候一定要经过编译的过程:

JSX —使用react构造组件,bable进行编译—> JavaScript对象 — ReactDOM.render()—>DOM元素 —>插入页面

组件中DOM样式

  • 行内样式

想给虚拟dom添加行内样式,需要使用表达式传入样式对象的方式来实现:

// 注意这里的两个括号,个表示我们在要JSX里插入JS了,第二个是对象的括号 <p style={{color:'red', fontSize:'14px'}}>Hello world</p>

行内样式需要写入一个样式对象,而这个样式对象的位置可以放在很多地方,例如render函数里、组件原型上、外链js文件中

  • 使用class

React推荐我们使用行内样式,因为React觉得每一个组件都是一个独立的整体

其实我们大多数情况下还是大量的在为元素添加类名,但是需要注意的是,class需要写成className(因为毕竟是在写类js代码,会收到js规则的现在,而class是关键字)

<p className="hello" style = {this.style}>Hello world</p>

  • 不同的条件添加不同的样式

有时候需要根据不同的条件添加不同的样式,比如:完成状态,完成是绿色,未完成是红色。那么这种情况下,我们推荐使用classnames这个包:

  • css-in-js

styled-components是针对React写的一套css-in-js框架,简单来讲就是在js中写css。npm链接

TodoList

组件化开发React todolist, 项目开发中的组件的基本目录结构基本上是这样的:

 

React学习笔记(一)

注意:一个组件只干一件事情 ,所以TodoList和TodoItem要做成两个组件,这样也方便于后期理解shouldComponentUpdate

 

好程序员公众号

  • · 剖析行业发展趋势
  • · 汇聚企业项目源码

好程序员开班动态

More+
  • HTML5大前端 <高端班>

    开班时间:2021-04-12(深圳)

    开班盛况

    开班时间:2021-05-17(北京)

    开班盛况
  • 大数据+人工智能 <高端班>

    开班时间:2021-03-22(杭州)

    开班盛况

    开班时间:2021-04-26(北京)

    开班盛况
  • JavaEE分布式开发 <高端班>

    开班时间:2021-05-10(北京)

    开班盛况

    开班时间:2021-02-22(北京)

    开班盛况
  • Python人工智能+数据分析 <高端班>

    开班时间:2021-07-12(北京)

    预约报名

    开班时间:2020-09-21(上海)

    开班盛况
  • 云计算开发 <高端班>

    开班时间:2021-07-12(北京)

    预约报名

    开班时间:2019-07-22(北京)

    开班盛况
IT培训IT培训
在线咨询
IT培训IT培训
试听
IT培训IT培训
入学教程
IT培训IT培训
立即报名
IT培训

Copyright 2011-2023 北京千锋互联科技有限公司 .All Right 京ICP备12003911号-5 京公网安备 11010802035720号