React 0基础学习路线(1)—初识React和JSX

重点大纲提炼

  • JSX
    • 声明式UI编写
    • 语法
      • 怎么输出数据
      • {表达式}
      • 针对不同的数据输出会有不同的表现
      • 列表
      • 逻辑输出

React介绍

img

  一个用于构建用户界面的 JavaScript

起源

  React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,做出来以后,发现这套东西很好用,就在2013年5月开源了,随后越来越多人开始关注和使用 React,慢慢的 React 就成为了当前最流行的前端开发框架之一。

特点

  • React 采用了声明式编程范式,可以更加方便的构建 UI 应用
  • 内部封装更加高效的与底层DOM进行交互的逻辑,提高性能的同时也能帮助我们更加专注于业务
  • 可以很好的接纳其它框架或库与其进行配合

React 全家桶

  • React : 提供框架(库)核心功能,如 组件虚拟DOM
  • create-react-app : 脚手架,提供一套用于快速 构建和打包 React 项目的工具
  • react-router : 基于 React 的路由库
  • redux、react-redux : 状态管理库

初识 React 与 JSX

加载引入

  • 基于浏览器 <script> 的模式
  • 基于自动化的集成环境模式

基于浏览器 script 的模式

React.js 框架本身包含两个部分

  • react.js:提供 React.js 核心功能代码,如:虚拟 dom,组件
    • 封装了很多底层的函数,核心类,但这些通通都与环境无关,跟操作浏览器原生app无关的一些东西,而是核心的东西。
    • 除此之外还提供了react dom,它提供了对不同环境的封装,比如dom操作。即主件这个东西,本身是与浏览器无关的,它只是定义了一个主件结构,放在核心库中。像虚拟dom,通通与浏览器无关,无论在浏览器中用,还是在原生app中用,它都有组件的概念和组件的代码
    • react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码(React不只是仅仅在浏览器中去应用,<React Native>同时还可以运用在手机端
  • react-dom.js:提供了与浏览器交互的 DOM 功能,如:dom 渲染
    • 基于web的,封装与浏览器打交道的相关代码,渲染,事件

起手式:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 
    <div id="app"></div>
 

    <script src="./js/react.development.js"></script>
    <script src="./js/react-dom.development.js"></script>
    <script src="./src/1.js"></script>
 
    <script>
        // 类似模板引擎的render,是渲染界面用的!
        // 第一个参数:渲染的内容 第二个参数:渲染内容放置在页面的什么位置
        ReactDOM.render(
             //'<div>我要渲染的内容</div>',
            '我要渲染的内容',
            document.querySelector('#app')
        );
    </script>
</body>
</html>

  我们不能仅仅渲染字符串,而需要渲染html元素等。

image-20200530211511587
// 类似模板引擎的render,是渲染界面用的!
// 第一个参数:渲染的内容 第二个参数:渲染内容放置在页面的什么位置
ReactDOM.render(
    '<div>我要渲染的内容</div>',
    // '我要渲染的内容',
    document.querySelector('#app')
);

  发现达不到预期结果,它只能最终解析为字符串!为什么这样设计呢?参考下面的**XSS**

  为了更方便输出html以及为后续的一些功能作准备,如组件化、虚拟dom,在这里它提供了一套新的模板语法。

image-20200530211723370
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
 
    <div id="app"></div>
 
    <script src="./js/react.production.min.js"></script>
    <script src="./js/react-dom.production.min.js"></script>
    <script src="js/app.js"></script>
</body>
</html>

js/app.js

ReactDOM.render(
    '<div>我要渲染的内容</div>',
    document.getElementById('app')
);

ReactDOM.render

ReactDOM.render(element, container[, callback])

element:要渲染的内容

container:要渲染的内容存放容器

callback:渲染后的回调函数

XSS

  为了有效的防止 XSS 注入攻击,React DOM 会在渲染的时候把内容(字符串)进行转义,所以字符串形式的标签是不会作为 HTML 标签进行处理的

编程范式

  就是编程的一种模式,比较流行的一些编程范式

  • 命令式编程
  • 声明式编程
  • 函数式编程

命令式编程

  告诉计算机怎么做(How?) - 过程

  在前面所学的原生 WebComponent 中,我们 UI 的构建是使用了命令式的编程方式来完成的

let shadow = this.attachShadow({mode: 'open'});
 
let style = document.createElement('style');
style.textContent = `span {color:red}`;
 
let span = document.createElement('span');
span.innerHTML = '我是自定义元素的内容';
span.classList.add('cred');
 
shadow.appendChild(style);
shadow.appendChild(span);

声明式编程

  告诉计算机我们要什么(What?) - 结果

SELECT * FROM `USER` WHERE `gender`='男' ORDER BY `age` DESC;

  上面的 SQL 就是一个典型的声明式编程,告诉数据库,我要什么结果,至于怎么查询出来结果,排序如何实现的过程 SQL 并不关心,由内部(底层)实现

['k',1,2,'k',true,'b'].filter(v => Number.isFinite(v)).map(v=>v*10).reduce((c, v)=>c + v, 0);

React.js 中的声明式 UI

<span className="cred">我是自定义元素的内容</span>

使用 JSX

JSX 是一个基于 JavaScript + XML 的一个扩展语法

  • 它可以作为 使用
  • 它并不是 字符串
  • 它也不是 HTML
  • 它可以配合 JavaScript 表达式 一起使用

js/app.js

ReactDOM.render(
    <div>我要渲染的内容</div>,
    document.getElementById('app')
);

引入 JSX 解析库

  babel-standalone.js:在浏览器中处理 JSX

<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel" src="js/app.js"></script>

注意:如果包含或引入的代码中包含 JSX ,需要设置 script 标签的 type 属性为:text/babel

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <div id="app"></div>

    <!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
    <script src="./js/react.development.js"></script>
    <!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
    <script src="./js/react-dom.development.js"></script>
    <!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts等语法   -->
    <script src="./js/babel.min.js"></script>

    <!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
    <script type="text/babel">
        /**
         * JSX
         *  JavaScript + XML
         */
        ReactDOM.render(
            <div>我要渲染的内容</div>,
            document.querySelector('#app')
        );
    </script>

</body>
</html>

image-20200628150518884

DOM 对象与 Virtual DOM

  JSX 通过编译器会最终转成一个对象给我们 - VDOM(虚拟DOM)

DOM 对象

  浏览器会把页面中的元素映射为 JavaScript 中的对象,在 JavaScript 中通过对这些对象的访问来获取页面中对应元素及其内容。同时,对这些对象进行某些操作,又会反馈到页面中对应的元素上面。

  但是,原生 JavaScript DOM 对象内容和结构太复杂,有很多的特性是我们平时很少用到的,而且我们对对象的操作会立即反馈到页面(渲染),影响性能

虚拟 DOM

  virtual DOM,参考原生 DOM 对象构建的一个对象,它的结构足够简单,同时优化渲染逻辑,减少变化带来的渲染性能影响

const App = (
    <div>
        <h1>开发</h1>
        <p>web前端高级工程师</p>
    </div>
);

  生成的 virtual DOM 结构如下:

image-20200628144131129

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <div id="app"></div>

    <!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
    <script src="./js/react.development.js"></script>
    <!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
    <script src="./js/react-dom.development.js"></script>
    <!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
    <script src="./js/babel.min.js"></script>

    <!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
    <script type="text/babel">
        /**
         * JSX
         *  JavaScript + XML
         *
         * JSX 通过编译器会最终转成一个对象给我们 - VDOM(虚拟DOM)
         */
        let div = <div>我要渲染的内容</div>;
        console.log(div);

        ReactDOM.render(
            div,
            document.querySelector("#app")
        );
    </script>

</body>
</html>

  这就是实际上的虚拟dom了。

image-20200628151408417

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <div id="app"></div>

    <!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
    <script src="./js/react.development.js"></script>
    <!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
    <script src="./js/react-dom.development.js"></script>
    <!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
    <script src="./js/babel.min.js"></script>

    <!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
    <script type="text/babel">
        /**
         * JSX
         *  JavaScript + XML
         *
         * JSX 通过编译器会最终转成一个对象给我们 - VDOM(虚拟DOM)
         */
        let div = <div>我要渲染的内容</div>;
        let appElement = document.querySelector('#app');

        console.dir(appElement);
        console.log(div);

        ReactDOM.render(
            div,
            // document.querySelector("#app")
            appElement
        );
    </script>

</body>
</html>

  我们这样就看到真实dom元素了,它是页面中真实存在的dom对象。这个对象表示了页面的一些元素的信息,但是原生当中的dom对象东西特别多,非常复杂。实际上在做模板渲染的时候,压根不需要如此多的信息。我们最需要关注的几个信息:

  1. 啥标签?
  2. 标签类型:文本/元素
  3. 标签属性
  4. 标签嵌套内容

  我们通过模板写的标签,直接会被react转换为虚拟dom。因为真实dom比较大,一定程度上会影响性能等因素。毕竟操作dom的开销是比较大的,所以jsx首先做的事情,就是把模板转化成虚拟dom。在必要的时候,再把虚拟dom变为真实dom。在这个整个过程当中,对页面当中一些操作,如对数据的一些变更,都会使模板发生变化。模板变化以后,react会判断哪些地方是需要更新的,哪些地方树不需要更新的,而且判断是基于很小的虚拟dom进行的,所以开销相对于原生js而言很小。即用一个很小的对象,降低dom频繁更新频繁操作带来的性能损耗问题。

image-20200628151622192

  虚拟dom大致结构:

let div = <div id="div1" style={{color: 'red'}}><span>我要渲染的内容</span><strong>123</strong></div>;
{
    type: 'div',
        props: {id: 'div1'}
        .....(存放标签中的各个属性)

}

该对象的props有一个id为’div1’。

style是一个对象属性,存放样式。

children是标签里面嵌套的内容。

image-20200628153926775

  我们仔细观察,里面的嵌套的children,有时一个虚拟dom,是层层嵌套的结构。

image-20200628154253184

  最终ReactDOM.render利用虚拟dom的结构去渲染页面,它会遍历该对象,首先看type,根据type如果是div就利用原生js创建一个div。紧接着再看它的props下的children,就这样层层递归的去创建。最后将创建好的真实dom渲染到指定的appElement元素里面去。

JSX 语法规则

结构

  每一个独立 JSX 结构的顶层有且只能有一个顶级父元素

// 错误
const App = (
  <div>
      <h1>开发</h1>
    <p>web前端高级工程师</p>
  </div>
  <div>第二个</div>
);
 
// 正确
const App = (
  <div>
    <div>
      <h1>开发</h1>
      <p>web前端高级工程师</p>
    </div>
    <div>第二个</div>
  </div>
);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let appElement = document.querySelector('#app');

    // 正确结构
    let div1 = <div>
        这是内容1
    </div>;

    let div2 = <div>
        这是内容2
    </div>;
    
    // div3的结构是错误的
    let div3 = <div>111</div><div>222</div>;

    ReactDOM.render(
        div,
        appElement
    );
</script>

</body>
</html>

image-20200628155727885

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let appElement = document.querySelector('#app');

    // 正确结构
    let div1 = <div>
        这是内容1
    </div>;

    let div2 = <div>
        这是内容2
    </div>;

    // div3的结构是错误的
    // let div3 = <div>111</div><div>222</div>;

    ReactDOM.render(
        <div>
            {div1}{div2}
        </div>,
        appElement
    );
</script>

</body>
</html>

image-20200628155937811

JSX 中嵌入表达式(插值表达式)

  在 JXS 中可以使用 {表达式} 嵌入JavaScript表达式(与VUE一样)

表达式:产生值的一组代码的集合

  • 变量
  • 算术运算
  • 函数调用
  • ……
let name = '开发岗位';
let title = 'web前端高级工程师';
const App = (
    <div>
        <h1>{name}</h1>
        <p>{title}</p>
    </div>
);

注意:分清楚 表达式语句 的区别,ifforwhile 这些都是语句,JSX 不支持语句

<h1>{if (true) {...}</h1>    // 错误
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let appElement = document.querySelector('#app');

    let name = '开发岗位';
    let title = 'web前端高级工程师';

    // 正确结构
    let div1 = <div>
        这是内容1{name}
    </div>;
    let div2 = <div>
        这是内容2{title}
    </div>;

    // div3的结构是错误的
    // let div3 = <div>111</div><div>222</div>;

    ReactDOM.render(
        <div>
            {div1}{div2}
        </div>,
        appElement
    );
</script>

</body>
</html>

image-20200628160227159

  还可以用算术运算表达式嵌入:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let appElement = document.querySelector('#app');

    let name = '开发岗位';
    let title = 'web前端高级工程师';

    // 正确结构
    let div1 = <div>
        这是内容1{name}
    </div>;
    let div2 = <div>
        这是内容2{title}
    </div>;

    // div3的结构是错误的
    // let div3 = <div>111</div><div>222</div>;

    ReactDOM.render(
        <div>
            {div1}{div2}
            <hr />
            {1+1}
        </div>,
        appElement
    );
</script>

</body>
</html>

image-20200628160406248

  除此之外,还有函数调用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let appElement = document.querySelector('#app');

    let name = '开发岗位';
    let title = 'web前端高级工程师';

    // 正确结构
    let div1 = <div>
        这是内容1{name}
    </div>;
    let div2 = <div>
        这是内容2{title}
    </div>;

    // div3的结构是错误的
    // let div3 = <div>111</div><div>222</div>;

    ReactDOM.render(
        <div>
            {div1}{div2}
            <hr />
            {1+1}
            <hr />
            {Math.random()}
        </div>,
        appElement
    );
</script>

</body>
</html>

image-20200628160535244

JSX 语法示例

  在 JSX 中,表达式输出的内容类型与使用位置也有一些区别

JSX 中的注释

<div>
      {/*注释*/}
      {/*
              多行注释
      */}
</div>

输出数据类型

  • 字符串数字:原样输出
  • 数组:转成字符串,数组.join(’’)
    • 使用 空字符串 而不是默认的 逗号 连接
  • 其它对象不能直接输出
  • 布尔值未定义 会被忽略

  看一下数组表达式输出:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let appElement = document.querySelector('#app');

    let name = '开发岗位';
    let title = 'web前端高级工程师';

    // 正确结构
    let div1 = <div>
        这是内容1{name}
    </div>;
    let div2 = <div>
        这是内容2{title}
    </div>;

    // div3的结构是错误的
    // let div3 = <div>111</div><div>222</div>;

    ReactDOM.render(
        <div>
            {div1}{div2}
            <hr />
            {1+1}
            <hr />
            {Math.random()}
            <hr />
            {['a','b','c']}
        </div>,
        appElement
    );
</script>

</body>
</html>

  实际这里内部调用了类似数组.join(''),使用空字符代替了逗号连接。

image-20200628160724104

['a','b','c'].toString()

image-20200628160914195

  假如想输出对象:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let appElement = document.querySelector('#app');

    let name = '开发岗位';
    let title = 'web前端高级工程师';
    let user = {username: 'ls', gender: '男'};

    // 正确结构
    let div1 = <div>
        这是内容1{name}
    </div>;
    let div2 = <div>
        这是内容2{title}
    </div>;

    // div3的结构是错误的
    // let div3 = <div>111</div><div>222</div>;

    ReactDOM.render(
        <div>
            {div1}{div2}
            <hr />
            {1+1}
            <hr />
            {Math.random()}
            <hr />
            {['a','b','c']}
            <hr />
            {user}
        </div>,
        appElement
    );
</script>

</body>
</html>

报错了!

image-20200628161113602

如何把数组输出ulli的形式:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let appElement = document.querySelector('#app');

    let name = '开发岗位';
    let title = 'web前端高级工程师';
    let user = {username: 'ls', gender: '男'};
    let list = ['aaa', 'bbb', 'ccc'];

    // 正确结构
    let div1 = <div>
        这是内容1{name}
    </div>;
    let div2 = <div>
        这是内容2{title}
    </div>;

    // div3的结构是错误的
    // let div3 = <div>111</div><div>222</div>;

    function renderList() {
            let lis = [];

            list.forEach( item => {
                lis.push(<li>{item}</li>);
            } );

            // [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
            return lis;
    }

    ReactDOM.render(
        <div>
            {div1}{div2}
            <hr />
            {1+1}
            <hr />
            {Math.random()}
            <hr />
            {['a','b','c']}
            <hr />
            {/*user*/}
            <hr />
            <ul>
                {renderList()}
            </ul>
        </div>,
        appElement
    );
</script>

</body>
</html>

警告是key的缘故,暂时放下。

image-20200628162237722

这个方法我们还可以进行简化:

function renderList() {
    return list.map( item => <li>{item}</li> );
}

image-20200628162237722

其实没必要套函数,直接用就行。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let appElement = document.querySelector('#app');

    let name = '开发岗位';
    let title = 'web前端高级工程师';
    let user = {username: 'ls', gender: '男'};
    let list = ['aaa', 'bbb', 'ccc'];

    // 正确结构
    let div1 = <div>
        这是内容1{name}
    </div>;
    let div2 = <div>
        这是内容2{title}
    </div>;

    // div3的结构是错误的
    // let div3 = <div>111</div><div>222</div>;

    // function renderList() {
    //         let lis = [];
    //
    //         list.forEach( item => {
    //             lis.push(<li>{item}</li>);
    //         } );
    //
    //         // [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
    //         return lis;
    // }

    // function renderList() {
    //     return list.map( item => <li>{item}</li> );
    // }

    ReactDOM.render(
        <div>
            {div1}{div2}
            <hr />
            {1+1}
            <hr />
            {Math.random()}
            <hr />
            {['a','b','c']}
            <hr />
            {/*user*/}
            <hr />
            <ul>
                {list.map( item => <li>{item}</li> )}
            </ul>
        </div>,
        appElement
    );
</script>

</body>
</html>

image-20200628162237722

在属性上使用 表达式

JSX 中的表达式也可以使用在属性上,但是使用的时候需要注意

  • 当在属性中使用 {} 的时候,不要使用引号包含
let id = 'aaaaaa';
 
// 错误
const App = (
    <div id="{id}"></div>
);
 
// 正确
const App = (
    <div id={id}></div>
);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let appElement = document.querySelector('#app');

    let name = '开发岗位';
    let title = 'web前端高级工程师';
    let user = {username: 'ls', gender: '男'};
    let list = ['aaa', 'bbb', 'ccc'];
    let divId = 'aaaaa';

    // 正确结构
    let div1 = <div>
        这是内容1{name}
    </div>;
    let div2 = <div>
        这是内容2{title}
    </div>;

    // div3的结构是错误的
    // let div3 = <div>111</div><div>222</div>;

    // function renderList() {
    //         let lis = [];
    //
    //         list.forEach( item => {
    //             lis.push(<li>{item}</li>);
    //         } );
    //
    //         // [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
    //         return lis;
    // }

    // function renderList() {
    //     return list.map( item => <li>{item}</li> );
    // }

    ReactDOM.render(
        <div>
            {div1}{div2}
            <hr />
            {1+1}
            <hr />
            {Math.random()}
            <hr />
            {['a','b','c']}
            <hr />
            {/*user*/}
            <hr />
            <ul>
                {list.map( item => <li>{item}</li> )}
            </ul>
            <hr />
            <div id={divId}>CSDN</div>
        </div>,
        appElement
    );
</script>

</body>
</html>

image-20200628163420367

  • JSX 更偏向 JavaScript, 所以对于一些特殊的属性,使用的是 JavaScript 中的属性名风格
// 错误
const App = (
    <div class="box1"></div>
);
// 正确
const App = (
    <div className="box1"></div>
);
  • 为了更加方法的操作元素的 style,针对 style 这个属性有特殊的处理
const App = (
    <div style={{width: '100px', height: '100px', color:'red'}}></div>
);

  这里的两个 {{}} ,外部的大括号表示的是前面说的表达式语法中的大括号,里面的大括号是表示对象的大括号

let skin = {width: '100px', height: '100px', color:'red'};
const App = (
    <div style={skin}></div>
);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let appElement = document.querySelector('#app');

    let name = '开发岗位';
    let title = 'web前端高级工程师';
    let user = {username: 'ls', gender: '男'};
    let list = ['aaa', 'bbb', 'ccc'];
    let divId = 'aaaaa';
    let style = {color: 'red', background: 'yellow'};

    // 正确结构
    let div1 = <div>
        这是内容1{name}
    </div>;
    let div2 = <div>
        这是内容2{title}
    </div>;

    // div3的结构是错误的
    // let div3 = <div>111</div><div>222</div>;

    // function renderList() {
    //         let lis = [];
    //
    //         list.forEach( item => {
    //             lis.push(<li>{item}</li>);
    //         } );
    //
    //         // [<li>aaa</li>,<li>bbb</li>,<li>ccc</li>]
    //         return lis;
    // }

    // function renderList() {
    //     return list.map( item => <li>{item}</li> );
    // }

    ReactDOM.render(
        <div>
            {div1}{div2}
            <hr />
            {1+1}
            <hr />
            {Math.random()}
            <hr />
            {['a','b','c']}
            <hr />
            {/*user*/}
            <hr />
            <ul>
                {list.map( item => <li>{item}</li> )}
            </ul>
            <hr />
            <div id={divId}>CSDN</div>
            <hr />
            <p style={style}>这是内容</p>
            <p style={{color: 'red', background: 'yellow'}}>这是内容</p>
        </div>,
        appElement
    );
</script>

</body>
</html>

image-20200628163931622

列表渲染

  如果需要渲染一组数据,我们可以通过遍历(数组遍历、对象变量……)等操作,返回一组 JSX

数据

let lisi = {
  name: '李四',
  gender: '男',
  skills: ['JavaScript', 'Node.js'],
  interests: ['音乐', '足球', '编程']
};
数组
function getSkills() {
  return (
    <ul>
      {lisi.skills.map(skill => <li>{skill}</li>)}
    </ul>
  );
}
const App = (
    <div>{getSkills()}</div>
);
// 或者
const App = (
    <div>
            <ul>
              {lisi.skills.map(skill => <li>{skill}</li>)}
            </ul>
      </div>
);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts等语法   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let lisi = {
        name: '李四',
        gender: '男',
        skills: ['JavaScript', 'Node.js'],
        interests: ['音乐', '足球', '编程']
    };

    function getSkills() {
        return (
            <ul>
                {lisi.skills.map(skill => <li>{skill}</li>)}
            </ul>
        );
    }
    const App = (
        <div>{getSkills()}</div>
    );

    ReactDOM.render(
        App,
        document.querySelector('#app')
    );

</script>

</body>
</html>

image-20200628145358935

对象
function getKeys() {
    let arr = [];
    for (let k in lisi) {
        arr.push(<li>{k}</li>);
    }
    return arr;
}
 
const App = (
    <div>
            <ul>
              {getKeys()}
            </ul>
      </div>
);
// 或者
const App = (
    <div>
            <ul>
              {Object.keys(lisi).map(key => <li>{key}</li>)}
            </ul>
      </div>
);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts等语法   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">
    let lisi = {
        name: '李四',
        gender: '男',
        skills: ['JavaScript', 'Node.js'],
        interests: ['音乐', '足球', '编程']
    };

    function getKeys() {
        let arr = [];
        for (let k in lisi) {
            arr.push(<li>{k}</li>);
        }
        return arr;
    }

    const App = (
        <div>
            <ul>
                {getKeys()}
            </ul>
        </div>
    );

    ReactDOM.render(
        App,
        document.querySelector('#app')
    );

</script>

</body>
</html>

image-20200628145625654

以上代码,实际都会警告,实际是我们没有加key。

image-20200628145658014

key

默认情况下,React 从性能上考虑,会尽可能的复用结构,针对 同组可变列表 结构,为了避免出现某些方面的问题,通常会给每一个列表添加一个 唯一的 key

<ul>
{[{id:1,name:'lisi',id:2,name:'zhangsan'}].map(user => <li key={user.id}>{user.name}</li>)}
</ul>

注意:key 的值不推荐使用数组的下标,具体原因,末尾最后详细解释

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">

    let appElement = document.querySelector('#app');
    let list = ['aaa', 'bbb', 'ccc'];

    ReactDOM.render(
        <ul>
            {
                list.map( (item) => {
                    return <li>{item}</li>
                })
            }
        </ul>,
        appElement
    );
</script>

</body>
</html>

image-20200628164841414

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">

    let appElement = document.querySelector('#app');
    let list = ['aaa', 'bbb', 'ccc'];

    function List() {
        return <ul>
            {
                list.map( (item) => {
                    return <li><input type="checkbox"/> {item}</li>
                })
            }
        </ul>
    }

    ReactDOM.render(
        <List/>,
        appElement
    );
</script>

</body>
</html>

image-20200628165125226

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<!-- react.js: react的核心库,提供了组件,辅助函数等与具体环境无关的核心代码  -->
<script src="./js/react.development.js"></script>
<!--  react-dom.js:封装与浏览器打交道的相关代码,渲染,事件  -->
<script src="./js/react-dom.development.js"></script>
<!-- babel:语法转换工具,它可以把一些特定的语法转成js,比如,jsx,ts   -->
<script src="./js/babel.min.js"></script>

<!-- 让下面的代码不要直接通过浏览器来运行,同时还要指定babel来编译它们   -->
<script type="text/babel">

    let appElement = document.querySelector('#app');

    function List(props) {
        return <ul>
            {
                props.data.map( item => {
                    return <li><input type="checkbox" /> {item}</li>
                } )
            }
        </ul>
    }

    class App extends React.Component {

        constructor() {
            super();

            this.state = {
                list:['aaa', 'bbb', 'ccc']
            }
        }

        render() {
            return <div>
                <List data={this.state.list} />
                <button onClick={() => {
                    this.setState({
                        list: this.state.list.sort((a, b) => Math.random() - .5)
                    })
                }}>按钮</button>
            </div>
        }

    }

    ReactDOM.render(
        <App />,
        appElement
    );
</script>

</body>
</html>

  发现了奇怪的问题。li随机排序后,勾选状态原地不动。

  首先根据传进去的数据,会渲染页面li。当数据发生变化,页面就会更新。调用this.setState方法后就表明数据发生了变化,它就会更新与这个数据有关的所有组件。React不会刷新整个页面,而是更新变化的部分。但是仅仅更新变化的部分,有用吗?它还考虑了复用问题,为了让性能更优,它在这里尽可能的去复用结构。

  要是按照以前的思维,就是产生新的一组li覆盖旧的li,用innerHtml覆盖掉全部。

  我们仔细观察,发现变化的是内容。它并没有把li替换掉,li标签及里嵌套的input标签都不会变,它只变化需要变化的部分。React为什么这么做?完全是为了复用,为了不要频繁地移动、删除、修改元素,而尽可能地原位复用元素。这样做的话,是性能优化了,但是对于同组结构(同级别的兄弟节点)而言,就会带来很大的问题,特别是循环的过程中,循环生成的结构,会带来很多问题。如这里的勾选状态是在html上的,它与数据毫无关系,因此它不会根据数据而重新渲染,即勾选状态不会随着数据变化,实际上元素与数据没有关系。

  但是大部分情况下这种特效是很好的,但是在循环列表中,它是有问题的。为了解决这个问题,达到更高的复用性,就增加了一个key属性。key一定不能写死,它是用来标识数据与产生元素之间的关联性的,即它们之间的纽带和桥梁。但是key必须胃一值,否则也会识别不出关联性了。

                props.data.map( item => {
                    return <li key={item}><input type="checkbox" /> {item}</li>
                } )

  如果不关注这个特性,也可不用key。如循环一个列表,其上方没有checkbox,我们对其进行升序和降序排列,这个时候就没任何影响,因为我们需要显示的也是数据。但是如果数据与节点有关联的话,就必须使用key了。

  如果我们在这里使用索引为key,也是没有用的。因为索引也是可复用的,数据内容变化并不会带着索引的。

props.data.map( (item, index) => {
    return <li key={index}><input type="checkbox" /> {item}</li>
} )

条件渲染

function moreInterests() {
    if (lisi.interests.length > 2) {
        return <a href="#">更多</a>
    }
}
const App = (
        <div>
            爱好:{lisi.interests.map(interest=>{
            return <span style={{marginRight:"10px"}}>{interest}</span>
        })}
        {moreInterests()}
      </div>
);
三元运算符
const App = (
        <div>
            爱好:{lisi.interests.map(interest=>{
            return <span style={{marginRight:"10px"}}>{interest}</span>
        })}
        {lisi.interests.length > 2 ? <a href="#">更多</a> : null}
      </div>
);
与或运算符
const App = (
        <div>
            爱好:{lisi.interests.map(interest=>{
            return <span style={{marginRight:"10px"}}>{interest}</span>
        })}
                {lisi.interests.length > 2 && <a href="#">更多</a>}
                {lisi.interests.length < 4 || <a href="#">更多</a>}
      </div>
);


(后续待补充)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章