ReactJS入门(一)—— 初步认识React

news2024/11/25 2:44:17

React刚开始红的时候,由于对其不甚了解,觉得JSX的写法略非主流,故一直没打算将其应用在项目上,随着身边大神们的科普,才后知后觉是个好东西。

好在哪里呢?个人拙见,有俩点:

1. 虚拟DOM —— 在DOM树的状态需要发生变化时,虚拟DOM机制会将同一Event loop前后的DOM树进行对比(自然通过一系列高效的算法),如果俩个DOM树存在不一样的地方,那么React仅仅会针对这些不一样的区域(DOM diff)来进行响应的DOM修改,从而实现最高效的DOM操作和渲染。

如下图,我们修改了DOM树上一些节点(或UI组件)对应绑定的state(不知道state是什么没关系,后续我们会提及),React会即刻将其标记为“脏状态”,在一个Event loop结束时(即使过程中你对某个组件的state进行了多次修改),React会计算得出DOM树上需要修改的地方(“脏”了的地方,如下图红点)及其最终的状态,并仅仅针对这些地方进行一次性的重新渲染。

于是好处显而易见,并非每修改一次组件的state,就会重新渲染一次,而是在Event loop结束后做一次“秋后算账”,减少冗余的DOM操作。另外React只针对需要修改的地方来做新的渲染,而非重新渲染整个DOM树,自然效率很是不错。

2. 组件可嵌套,而且,可以模版化嘛 —— 其实在React里提及的“组件”,常规是一些可封装起来、复用的UI模块,说的接地气了可以理解为“带有细粒度UI功能的部分DOM区域”。然后我们可以把这些组件层层嵌套起来使用(当然这样组件间会存在依赖关系)。

至于模块化,类似于ejs那样可以作为独立的模块被引用到页面上来复用,不过咧,它可以直接把UI组件当作脚本模块那样来使用,咱完全可以配合CommonJS、AMD、CMD等规范来require需要的组件模块,并处理好它们的依赖关系(是不是碉堡了)。

基于上述的俩点,自然的也打算投入React怀抱了。不过在这之前得先理清俩点事情:

1. React是一个纯View层,不擅长于和动态数据打交道(哎哟咱也不谈Flux了,Flux的概念其实也不完善),因此它不同于,也替代不了常规的MV*框架;

2. React很擅长于处理组件化的页面,在页面上搭组件的形式有点像搭乐高一样,因此用上React的项目需求常规为界面组件化。另外React只支持到IE8+,就天朝的情况,是否使用React还是得稍微斟酌一番。

唠嗑了这么多,下面开始进入React的入门课程。本章提及的代码都可以在我的Github上下载到。

JSX

JSX是React编写组件的一种语法规范,可以看为是js的扩展,它支持将HTML和JS混写在一起,最终会通过React提供的 JSXTransformer.js 来将其编译为常规的js,方便浏览器解析。我们来个最简单的例子:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>最简单的jsx</title>
    <script src="react.js"></script>
    <script src="JSXTransformer.js"></script>
</head>
<body>
<div id="a">123</div>
<script type="text/jsx">
    var name = 'VaJoy';
    React.render(<h1>{name}</h1>, document.getElementById('a'));
</script>
</body>
</html>

页面上我们引入了 react.js 和 JSXTransformer.js 俩个重要的脚本,前者自然是react的核心,后者则是将JSX语法转为js语法。

实际上使用 JSXTransformer.js 在客户端来解析JSX语法是一件冗余、耗性能的事情,我们可以在上线项目之前,事先使用诸如 gulp-react 的工具先把所有的JSX均转换为js文件再引入到页面中。

当然如果你掌握了react的JS写法(当然相比JSX的学习成本要高不少),你可以直接在页面上书写相应的 原生js 即可,来个对比:

//使用JSX
React.render(
    <div>
        <div>
            <div>content</div>
        </div>
    </div>,
    document.getElementById('example')
);

//不使用JSX
React.render(
    React.createElement('div', null,
        React.createElement('div', null,
            React.createElement('div', null, 'content')
        )
    ),
    document.getElementById('example')

回到开头第一段代码段,我们将页面的JSX直接写在 <script type="text/jsx"> 中,注意 type 类型要标明为 "text/jsx" 。

然后我们定义了个变量name,并使用了React最基础和最常用的一个方法 React.render() 来渲染DOM:

    var name = 'VaJoy';
    React.render(<h1>{name}</h1>, document.getElementById('a'));

React.render() 支持两个参数(其实还有第三个可选的参数,作为渲染后的回调),第一个参数为模板的渲染内容(HTML形式),第二个参数表示要插入这段模板的DOM节点(DOM node)

这里要提及一个知识点 —— 在JSX中,遇到 HTML 标签(以 < 开头),将用 HTML 规则解析;遇到代码块(以 { 开头),则用 JavaScript 规则解析。所以我们在<h1>中嵌入变量 name 时是以花括号的形式 {name} 来实现的。

至于执行结果,相信大家很容易猜出来:

即往div里插入了(其实应该说是彻底替换为)JSX中的模板内容(<h1>元素)

鉴于JSX支持HTML跟JS的混写,故其灵活性很高,我们试着把变量换为数组:

    var arr = ['HELLO', "here is", 123, "VaJoy`s blog"];
    React.render(
        <ul>{
            arr.filter(function(v){
                return typeof v === 'string'
            }).map(function(v){
                return <li> {v} </li>
            })
        }</ul>,
        document.getElementById('a')
    );

结果如下:

组件

开头已经提及React是用于组件化开发的,组件可看为是其最小组成单位,那么什么是组件(component)呢?我们看看下方这张图:

这是一个移动端上的UI界面,用于查询员工列表和某员工的具体信息。那么我们按页面上各功能来细分,以左侧的搜索主页界面而言,可以把它细分为SearchBar、EmployeeList、EmployeeListItem等UI组件,其中EmployeeList组件嵌套了多个EmployeeList组件,而这众多组件的搭配组成了整个Hompage界面。

常规我们用React开发的页面可以看为一个大组件,它由多个小组件搭建而成。

在JSX中,我们可以通过 React.createClass() 方法来创建一个组件(注意组件的名称必须为大写字母开头),并以命名标签的形式(<MyClassName />)来引用:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>组件</title>
    <style>
        .nameStyle{
            color: dodgerblue;
        }
    </style>
    <script src="react.js"></script>
    <script src="JSXTransformer.js"></script>
</head>
<body>
<div id="a"></div>
<script type="text/jsx">
    var name = 'VaJoy';
    var Demo = React.createClass({  //随便建了个叫Demo的组件
        render: function() {  //每个组件都需要有自己的render方法
            var a = "Hello,";
            return (
                <p className="nameStyle" >{a,name}</p> //当然你可以写为{a}{name}
            );
        }
    });
    React.render(
        <Demo />,  //引入组件Demo
        document.getElementById('a')
    );
</script>
</body>
</html>

注意每个组件都需要有一个render方法,用于输出组件内容。另外组件DOM元素上的 class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。

执行效果如下:

可以看到,如果在一个容器中引用了多个变量,React会对应每个文本节点来自动生成对应span标签(React防止XSS的机制,因此要注意规避span的样式污染!)

再来看个组件嵌套的示例,其实都很简单:

 View Code

注意在JSX里,给DOM设置 style 必须写成 {{ marginRight : '10px', fontSize : '18px' }} 的映射形式(预防XSS),否则会报错

执行结果(注意连空格都生成了一个span)

组件的“数据”

我们在前头提及了,React只是一个纯view层,并不涉及model。不过但对于React组件而言,它有两种特殊的data —— Props 和 States。其中的 States 有点类似于各MV*框架中的model部分,可以称为React的状态机制,用于与用户进行交互。

1. Props

props表示组件自身的属性,也可以用于在嵌套的内外层组件中传递信息(常规是由父层组件传递给子层组件)。要注意它是不变的、也不应该尝试去改变的。我们来个简单的示例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>组件Props</title>
    <script src="react.js"></script>
    <script src="JSXTransformer.js"></script>
</head>
<body>
<div id="a"></div>
<script type="text/jsx">
    var Component1 = React.createClass({
        render: function() {
            return <p> {this.props.abc, this.props.name} </p>;
        }
    });
    var Component2 = React.createClass({
        render: function() {
            return (
                    <div className="commentList" onClick={this.handleClick}>
                        <Component1 abc="你好!" name="张三" />
                        <Component1 abc="Hi!" name="李四" />
                    </div>
            );
        },
        handleClick: function (e) {
            console.log(this.props.name, e.target);
        }
    });
    React.render(
        <Component2 name="我是Component2的name哦!" />,
        document.getElementById('a')
    );
</script>
</body>
</html>

这里我们注册了俩个组件类 Component1 和 Component2 ,其中 Component2 内嵌了 Component1 。

我们先看 Component1 的定义:

    var Component1 = React.createClass({
        render: function() {
            return <p> {this.props.abc, this.props.name} </p>;
        }
    });

它返回了一个p标签,其中的内容是 this.props.abc 和 this.props.name,这里的 this 指的是组件 Component1 本身,因此比如 this.props.name 获取到的便是组件 Component1 自身的属性 name 的值(abc 和 name 的值我们都在 Component2 中进行了定义)。

我们接着看 Component2:

    var Component2 = React.createClass({
        render: function() {
            return (
                    <div className="commentList" onClick={this.handleClick}>
                        <Component1 abc="你好!" name="张三" />
                        <Component1 abc="Hi!" name="李四" />
                    </div>
            );
        },
        handleClick: function (e) {
            console.log(this.props.name, e.target);
        }
    });

在这里我们除了嵌入组件 Component1 并定义了它们的属性值 abc 和 name ,也使用了React的事件机制——我们用 onClick 方法来触发点击事件,其对应的 this.handleClick 是我们自定义的一个方法,用于输出 Component2 的 name 属性和当前被点击的目标元素。

最后我们用 React.render 方法渲染组件 Component2 ,并定义了它的 name 属性:

    React.render(
        <Component2 name="我是Component2的name哦!" />,
        document.getElementById('a')
    );

执行结果如下:

这里有点要留意的,无论是 props 组件属性,或者是 onClick 事件,都是 React 内部的东西,我们在HTML上是看不到它们的:

顺便提个Props的语法糖 —— 我们可以通过 “...this.props” 来将父层组件绑定的全部属性都直接写到子组件中:

 View Code

执行结果:

Props也并非都是直接写在组件标签上的属性,有一个例外 —— props.children,它表示当前组件的所有子节点(它们常规是在外部的组件赋予的)

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>props.children</title>
    <style>
        p:active{ color: deeppink; }
    </style>
    <script src="react.js"></script>
    <script src="JSXTransformer.js"></script>
</head>
<body>
<div id="a"></div>
<script type="text/jsx">
    var Component1 = React.createClass({
        render: function() {
            return <li>{this.props.children}</li>
        }
    });
    var Component2 = React.createClass({
        list: ['张三', '李四', '王五'],
        render: function() {
            return (
                <ul>
                    {
                        this.list.map(function(item){
                            return <Component1>{item}</Component1>
                        })
                    }
                </ul>
            );
        }
    });
    React.render(
        <Component2 />,
        document.getElementById('a')
    );
</script>
</body>
</html>

留意第27行的代码 return <Component1>{item}</Component1> ,其中的{item}会作为组件Component1的子节点(即 props.children)来处理。

执行如下:

2. State

State 是组件的状态,它是可变的,因此常用于跟用户的交互。

不同于Props,我们需要在组件中使用 getInitialState() 方法来初始化组件的State,并使用 this.setState() 来修改State的值:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>state</title>
    <style>
        p:active{ color: deeppink; }
    </style>
    <script src="react.js"></script>
    <script src="JSXTransformer.js"></script>
</head>
<body>
<div id="a"></div>
<script type="text/jsx">
    var Component = React.createClass({
        getInitialState: function() {
            return {
                isClick: !1
            }
        },
        render: function() {
            var text = this.state.isClick ? 'clicked!' : 'none click';
            return <div>
                <input type="checkbox" onChange={this.clickCb} />{ text }
            </div>;
        },
        clickCb: function(){
            this.setState({
                isClick : !this.state.isClick  //点击checkbox时改变state.isClick
            })
        }
    });

    React.render(
        <Component />,
        document.getElementById('a')
    );
</script>
</body>
</html>

我们先通过 getInitialState() 方法初始化了组件Component的State对象,里面有个 isClick 的属性,默认值为 false。

接着在组件的 render 方法里定义了一个 text 变量,其值会根据 state.isClick 的变化而变化:

var text = this.state.isClick ? 'clicked!' : 'none click';

另外给checkbox控件绑定了React的 onChange 事件,checkbox的勾选状态改变时触发组件的 clickCb 自定义回调事件,它是这样的:

        clickCb: function(){
            this.setState({
                isClick : !this.state.isClick  //点击checkbox时改变state.isClick
            })
        }

如注释,它会通过 this.setState 方法来改变 state.isClick 的值,进而依赖于 state.isClick 的变量 text 的值也会间接变化:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/614698.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

14.数据结构之多路查找树与堆

前言 之前介绍的都是二叉查找树&#xff0c;二叉树一个节点最多有两个子节点&#xff0c;那么多于两个节点是什么情况呢&#xff0c;这就是我们本节要介绍的多路查找树。 多路查找树&#xff0c;也是我们数据库mysql底层索引维护方式。下面&#xff0c;我们来详细介绍。 1. …

小红书母婴博主类型怎么选,类型区分

母婴类型的分享不管在哪个平台都是涨粉最快的&#xff0c;也可能是因为当前的大环境因素导致的。不过如果你想成为一名母婴博主或者想要借助它的影响&#xff0c;得先了解一些东西。那么小红书母婴博主类型怎么选&#xff0c;类型怎么区分。 小红书母婴博主是指聚集在小红书平台…

【数据结构】带你玩转排序:堆排序、希尔排序、插入排序、选择排序、冒泡排序、快排(多版本)、归并排序

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 常见算法的实现 插入排序 希尔排序 堆排序 选择排序 冒泡排序 快速排序 Hoare版本 随机选Keyi 三数取中 挖坑法 前后指针版本 归并排序 常见算法的实现 插入排序 动画演示&…

信创提速,人才为先!麒麟信安与领路信创签订《人才合作协议》

5月23日&#xff0c;麒麟信安杨涛董事长一行考察了设立在长沙领路信创科技有限公司&#xff08;简称&#xff1a;领路信创&#xff09;的“国家新一代自主安全计算系统产业集群人才基地”&#xff08;简称人才基地&#xff09;&#xff0c;并与领路信创刘耿董事长签署《人才合作…

苹果WWDC2023:首款MR头显震撼发布,开发者泪洒现场,一文读懂全新产品及创新功能

&#x1f337; 博主 libin9iOak带您 Go to New World.✨ &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &#x1f30a; 《IDEA开发…

macOS Sonoma 发布,全面提升生产力和创意工作流(ISO、IPSW、PKG 下载)

macOS Sonoma 14.0 Beta 1 (23A5257q) ISO、IPSW、PKG 下载 本站下载的 macOS 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安装&#xff0c;或者在虚拟机中启动安装。另外也支持在 Windows 和 Li…

chatgpt赋能python:Python如何删除行:从入门到精通

Python如何删除行&#xff1a;从入门到精通 在Python编程中&#xff0c;删除行是必不可少的操作之一。无论是清除不必要的数据&#xff0c;还是在数据集中删除重复行&#xff0c;或者在文本文件中删除某些行&#xff0c;删除行都是一项极其重要的任务。 什么是Python语言&…

shell文件读取

文件读取 一、whilefor shell中读取文件有两种方式 while 和 for while #!/bin/bash cat filename | while read line doetho $line donefor #!/bin/bash for line in cat filename(待读取的文件) doecho $line done第三中写法&#xff0c;上述两种方式的升级写法 #!/bin/bas…

SQL-约束

SQL-约束 1.1 概念 约束是作用于表中列上的规则&#xff0c;用于限制加入表的数据约束的存在保证了数据库中数据的正确性、有效性和完整性 1.2 分类 类型描述关键字非空约束保证列中所有的数据不能有null值NOT NULL唯一约束保证列中所有数据各不相同UNIQUE主键约束主键是一行…

HTTP首部(上)

HTTP 协议的请求和响应报文中必定包含 HTTP 首部&#xff0c;只是我们平时在使用 Web 的过程中感受不到它。本章我们一起来学习 HTTP 首部的结构&#xff0c;以及首部中各字段的用法。 1.HTTP报文首部 先来看看http报文的首部结构图&#xff1a; HTTP 协议的请求和响应报文中…

不知道如何搭建帮助中心?这里有解决办法!

在今天的数字化时代&#xff0c;帮助中心已经成为许多公司所必需的一个重要部分。它是一个客户与公司沟通和交互的重要渠道&#xff0c;可以帮助客户解决问题和获得支持。本文将介绍如何搭建一个有效的帮助中心&#xff0c;以提高客户满意度和公司的效率。 一、明确帮助中心的…

哪些因素对会影响到企业制定自己的融合CDN战略

我们知道一个企业/组织有多种方法可以实现和利用多CDN战略&#xff0c;由于带宽承诺、成本、超期费用等因素&#xff0c;因此对不同的指标进行评估至关重要。 以下是可能影响您的融合CDN战略的一些因素&#xff1a; 地理因素 在选择CDN时需要考虑的一个重要因素是用户所在的…

静态内存管理

内存管理的基本概念 在一般的实时嵌入式系统中&#xff0c;由于实时性的要求&#xff0c;很少使用虚拟内存机制。所有的内存都需要用户参与分配&#xff0c;直接操作物理内存&#xff0c;所分配的内存不能超过系统的物理内存&#xff0c;所有的系统堆栈的管理&#xff0c;都由…

快速上手kettle(三)壶中可以放些啥?

快速上手kettle&#xff08;三&#xff09;壶中可以放些啥&#xff1f; 序言一 、kettle这壶能装些啥二、Access输入2.1 准备Acess数据库和表2.2 新建一个转换并设置2.3 启动转换预览数据 三、CSV文件输入3.1 准备csv文件&#xff0c;并将csv输入控件拖入工作区3.2 csv输入控件…

JDBC 拾枝杂谈—入门篇(通俗易懂)

目录 一、前言 二、JDBC介绍 1.基本概述 : 2.基本原理 : 三、JDBC模拟 1.模拟接口 &#xff1a; 2.模拟实现类 : 3.模拟测试类 : 4.模拟扩展 : 四、JDBC入门 1.编写JDBC程序的核心四部曲 : &#xff08;全文背诵&#xff09; 2.准备工作 : ①导入jar包 ②创建测试表 …

Sys Tick【转】

STM32学习及应用笔记一&#xff1a;SysTick定时器学习及应用 - STM32/STM8技术论坛 - 电子技术论坛 - 广受欢迎的专业电子论坛! (elecfans.com) 1、SysTick究竟是什么&#xff1f; 关于SysTick在STM32的资料中并没有详细的介绍&#xff0c;这可能由于SysTick是ARM内核的东西。在…

在用对讲机中竟有近5成属于违规使用?

目前对讲机在很多领域和场景中都有着广泛的应用&#xff0c;包括建筑工地、宾馆饭店、住宅小区、大型商场超市、安保活动、物业管理等。 不过据非官方数据统计&#xff0c;在用对讲机中竟有近5成属于违规使用&#xff0c;这严重干扰了城市上空的无线电波秩序。 根据近年来无线…

多行 SQL 格式化换行调整(数据清洗、数据迁移)

多行 SQL 格式化换行调整&#xff08;数据清洗、数据迁移&#xff09; 原数据数据如下&#xff1a; select * from user_info;select * from user_info; select * from user_info;INSERT INTO student VALUES (107, zhao, NULL, 3, 北京); select * from user_info;INSERT INT…

哪个骨传导蓝牙耳机的好,几款高性能的骨传导蓝牙耳机分享清单

骨传导耳机是目前在运动领域最火热的产品&#xff0c;也是最适合运动的耳机&#xff0c;它的原理是通过颅骨将声音转化为神经冲动&#xff0c;通过内耳传至听觉中枢&#xff0c;因此不会对耳朵造成任何损伤&#xff0c;它同时也可以让耳朵更好地听到周围的声音。能够很好的提高…