ReactReact全家桶React 概述+虚拟DOM的创建与渲染+JSX

Posted 前端More

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReactReact全家桶React 概述+虚拟DOM的创建与渲染+JSX相关的知识,希望对你有一定的参考价值。

文章目录


参考链接:

1 React 概述

1.1 React 简介与特点

React用于动态构建用户界面的 JS 库(只关注于视图)

  • 是一个将数据渲染为 html 视图的开源 JS 库
  • 它遵循基于组件的方法,有助于构建可重用的 UI 组件
  • 它用于开发复杂的交互式的 web 和移动 UI

原生JS的缺点

  • 原生JS操作DOM繁琐,效率低直接操作DOM,浏览器会进行大量的重绘重排
  • 原生JS没有组件化编码方案,代码复用率很低

React的特点

  • 使用虚拟DOM和Diff算法,尽量复用DOM节点,减少与真实DOM的交互
  • 使用 JSX,代码的可读性更好
  • 组件化模式,提高代码复用率、且让代码更好维护
  • 声明式编程, 让编码人员无需直接操作DOM,提高开发效率
  • 在 React Native中可以使用React语法进行移动端开发

1.2 相关补充:命令式与声明式编程、重绘与重排、模块化与组件化、虚拟DOM

命令式编程与声明式编程

  • 命令式编程:命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现
  • 声明式编程:告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。

重绘与重排

  • 重绘(repaint):当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程
  • 重排(reflow):当DOM的变化影响了元素的几何信息(DOM对象的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置的过程

模块化与组件化

传统开发模式的主要问题:命名冲突、文件依赖, 通过模块化可解决上述问题

  • 模块: 一个JS文件就是一个模块,模块内部定义的变量和函数默认情况下在外部无法得到

  • 模块化: 把单独的一个功能封装到一个模块(js文件)中,模块之间相互隔离,但是可以通过特定的接口公开内部成员,也可以依赖别的模块

  • 优点: 方便代码的重用,从而提升开发效率,并且方便后期的维护

传统方式编写应用的问题:依赖关系混乱、代码复用率不高, 通过组件化可解决上述问题

  • 组件: 实现应用中局部功能代码和资源的集合 ,组件是可复用的React实例, 把一些公共的模块抽取出来,写成单独的组件,然后按需引入,提高了代码的复用率
  • 组件化: 一个界面的功能很复杂,将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得容易了,当应用是以多组件的方式实现, 这个应用就是一个组件化的应用。

虚拟DOM

虚拟DOM是JS按DOM(真实DOM)的结构来创建的虚拟树型结构对象,是对DOM的抽象,比DOM更加轻量型(属性更少),本质还是Object类型的对象,虚拟DOM最终会被React转化为真实DOM,呈现在页面上。

2 初识React

2.1 引入相关库

  • react.js:React核心库。

  • react-dom.js:提供操作DOM的React扩展库。

  • babel.min.js:解析JSX语法代码转为JS代码的库。

    • 浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行
    • 只要用了JSX,都要加上type="text/babel", 声明需要babel来处理

2.2 虚拟DOM的创建与渲染

JS 创建虚拟 DOM(一般不用)

<script type="text/JS" > 
//1.创建虚拟DOM,创建嵌套格式的dom
const VDOM=React.createElement('h1',id:'title',React.createElement('span',,'hello,React'))
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.querySelector('.test'))
</script>

JSX 创建虚拟DOM

//1.创建虚拟DOM
script type="text/babel" > /* 此处一定要写babel */
const VDOM = (  /* 此处一定不要写引号,因为不是字符串 */
    <h1 id="title">
		<span>Hello,React</span>
	</h1>
)
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.querySelector('.test'))
</script>

虚拟DOM的渲染

语法

//virtualDOM为虚拟dom  containerDOM用来包裹虚拟DOM的真实dom对象
ReactDOM.render(virtualDOM, containerDOM) 

作用: 将虚拟DOM渲染到页面中的真实容器DOM中显示

代码总览

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>hello_react</title>
</head>

<body>
  <!-- 真实DOM对象  根节点-->
  <div id="test"></div>

  <!-- 引入react核心库 -->
  <script type="text/JS" src="../js/react.development.js"></script>
  <!-- 引入react-dom,用于支持react操作DOM -->
  <script type="text/JS" src="../js/react-dom.development.js"></script>
  <!-- 引入babel,用于将jsx转为js -->
  <script type="text/JS" src="../js/babel.min.js"></script>

  <script type="text/babel"> /* 此处一定要写babel */
		//1.创建虚拟DOM
		const VDOM = <h1>Hello,React</h1>  /* 此处一定不要写引号,因为不是字符串 */
		//2.渲染虚拟DOM到页面
		ReactDOM.render(VDOM,document.getElementById('test'))
	</script>
</body>

</html>

3 JSX

3.1 JSX简介

JSX(JS XML)是一种类似于XML的JS扩展语法,用来简化创建虚拟DOM, 在React中可以方便地用来描述UI(用户界面) 。 JSX为我们提供了创建React元素方法(React.createElement(component, props, ...children))的语法糖(简写形式)

写法:

import React from 'react';
//JSX不是字符串, 也不是HTML/XML标签,最终产生的就是一个JS对象
var ele = <h1>Hello, JSX!</h1> 

// 等价于

var element = React.createElement(
  "h1",
  null,
  "Hello, world!"
);

注:

  • 定义虚拟DOM时,不要写引号。只有一个根标签且每个标签必须闭合

  • JSX 语法需要小括号( )包裹,避免遇到js自动插入分号的陷阱

  • 内联样式,要用 style= key:value 的形式去写。 React 提倡的是组件思想,万物皆是 JS 控制(用 JS 来写 HTML 和 CSS)。以组件为维度,把 HTML、CSS、JS 混合在一起。

    style=
         marginBottom: 40,//或'40px' 有px需要加' ' 
         width: 590, 
         height: 590,
         display: 'flex',
         float: 'left', 
         justifyContent: 'flex-end'
    
    

3.2 JSX的基本用法

3.2.1 JSX代表JS对象(Object)

JSX本身也是一个表达式,在编译后,JSX表达式会变成普通的JS对象(Object)。

你可以在if语句或for循环中使用JSX,你可以将它赋值给变量,你可以将它作为参数接收,你也可以在函数中返回JSX。

function getGreeting(user) 
  if (user) 
    return <h1>Hello, formatName(user)!</h1>;
  
  return <h1>Hello, Stranger.</h1>;

    
//上面的代码在if语句中使用JSX,并将JSX作为函数返回值。实际上,这些JSX经过编译后都会变成JS对象。经过babel会变成下面的js代码:
    
function test(user) 
    if (user) 
        return React.createElement(
            "h1",
            null,
            "Hello, ",
            formatStr(user),
            "!"
        );
    
    return React.createElement(
        "h1",
        null,
        "Hello, Stranger."
    );

3.2.2 在JSX中使用JS表达式

在 JSX 语法中,你可以在 内放置任何有效的JS表达式, 例如,2 + 2user.firstNameformatName(user) 都是有效的 JS 表达式。

function formatName(user) 
  return user.firstName + ' ' + user.lastName;


const user = 
  firstName: 'Harper',
  lastName: 'Perez'
;

const element = (
  <h1>
    Hello, formatName(user)!
  </h1>
);

ReactDOM.render(
  element,
  document.getElementById('root')
);

if语句以及for循环不是JS表达式,不能直接作为表达式写在 中,可以先将其赋值给一个变量(变量是一个JS表达式):

function NumberDescriber(props) 
  let description;
  if (props.number % 2 == 0) 
    description = <strong>even</strong>;
   else 
    description = <i>odd</i>;
  
  return <div>props.number is an description number</div>;

JSX还可自动防范注入攻击,在JSX中嵌入接收到的内容是安全的,在默认情况下,React DOM会将所有嵌入JSX的值进行编码。这样可以有效避免xss攻击。比如:

const danger = response.potentialDanger;
cosnt ele = <h1>title</h1>

相关补充 :js表达式与js语句

js表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方

判断方法:在它们左边定义一个变量 const x =xxx 若有返回值就是表达式

下面这些都是表达式:

  • a
  • a+b
  • demo(1) ( 函数调用表达式)
  • arr.map( )
  • x === y ? ‘a’ : ‘b’
  • function test ( )

js语句: 语句可以理解为一个行为,循环语句和判断语句就是典型的语句。下面这些都是语句:

  • if( )
  • for( )
  • switch( )case:xxxx

3.2.3 JSX属性值

可以使用引号字符串字面量指定为属性值或者可以将一个JS表达式嵌在一个大括号 中作为属性值:

//”0”是一个字符串字面量
const element = <div tabIndex="0"></div>

const element = <img src=user.avatarUrl></img>;
//这里用到的是JS属性访问表达式,上面的代码将编译为:
const element = React.createElement("img",  src: user.avatarUrl );

3.2.4 JSX的Children

一个标签里面没有内容,你可以使用 /> 来闭合标签 , JSX 标签里能够包含很多子元素 Children

const element = (
  <div>
    <h1>Hello!</h1>
    <img src=user.avatarUrl />
  </div>
);

标签属性名使用驼峰命名法camelCase , class== > className;,for== >Htmlfor , tabindex== >tabIndex

const element = <div className='demo'></div>

3.2.5 JSX中的props

每个组件都是一个对象,props是对象的一个属性,组件对象可以通过props传递

指定JSX中的props有以下几种方式:

  • 使用JS表达式,任何有效的JS表达式都可以作为props的值,使用的时候将该表达式放在一对大括号 中即可

    <MyComponent foo=1 + 2 + 3 + 4 />
    <YourComponent clickTodo=(id) => this.props.handleClick(id) />
    
  • 字符串字面量可以作为prop值

    <MyComponent message="hello world" />
    // 等价于
    <MyComponent message='hello world' />
    
  • 使用扩展运算符, 你想将一个prop对象传入JSX,你可以使用扩展运算符...直接将整个prop对象传入

    function App1() 
      return <Greeting firstName="Ben" lastName="Hector" />;
    
    
    // 等价于
    
    function App2() 
      const props = firstName: 'Ben', lastName: 'Hector';
      return <Greeting ...props />;
    
    

3.2.6 JSX标签体内容props.children

React组件中有一个特殊的prop–props.children。它指代了JSX表达式中标签体内容。

指定 JSX中的props.children 有以下几种方式:

  • 使用字符串字面量, 在JSX标签体中写入字符串字面量,组件得到的props.children就是该字符串值

    //MyComponent的props.chilren获得”Hello World!”字符串
    <MyComponent>Hello world!</MyComponent>
    
  • JSX元素作为children, 我们同样可以使用JSX元素作为JSX的children,由此生成嵌套组件 , 也可以混合使用字符串字面量和JSX作为children :

    <MyContainer>
      Here is a list:
      <MyFirstComponent />
      <MySecondComponent />
    </MyContainer>
    
  • JS表达式, 和props一样,你也可以将任何有效的JS表达式作为children传入,将它放在 中就可以了。

    <MyComponent>a+b</MyComponent>
    
  • 函数children, 传入自定义组件的children并没有严格的限制,只要在React需要render的时候能将它们转换成可以render的东西就行了

    function ListOfTenThings() 
      return (
        <Repeat numTimes=10>
        //作为一个prop传入
          (index) => <div key=index>This is item index in the list</div>
        </Repeat>
      );
    
    
  • 布尔值、Null以及Undefined, 布尔值,Null以及Undefined可以作为有效的children,但他们不会被render

    <div>
       // <Header />只有在showHeader为true时才会render
        showHeader && <Header />
        <Content />
    </div>
    

3.2.7 自定义组件与元素标签

遇到 < 开头的代码, 观察标签首字母:

  • 小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错。
  • 大写字母开头,React就去渲染对应的组件,若组件没有定义,则报错。
  • 自定义组件首字母要大写,一定引入后在使用,元素标签名不能使用表达式

以上是关于ReactReact全家桶React 概述+虚拟DOM的创建与渲染+JSX的主要内容,如果未能解决你的问题,请参考以下文章

ReactReact全家桶React 生命周期+虚拟DOM+Diff算法

ReactReact全家桶React 生命周期+虚拟DOM+Diff算法

ReactReact全家桶React Router 6

ReactReact全家桶之React Router6

ReactReact全家桶React脚手架

ReactReact全家桶React Hooks