React 1|学习笔记

简介: 快速学习React 1

开发者学堂课程【高校精品课-上海交通大学 -互联网应用开发技术React 1】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/76/detail/15744


REACT 1


内容介绍:

一、前言

二、相关下载和文献

三、Hello World

四、Web storm

五、介绍 JXS

六、渲染元素

七、组件和 Props

八、状态和生命周期


一、前言

这节课主要讲解 React 。在上节课当中简单的介绍了 Javascript 。如果在之前没有接触过 Javascript的话,可以先把它当成一门新语言去学习,接下来继续去练习。


二、相关下载和文献

1. 下载

https://github.com/facebook/react/ 是可以进行下载的网址,在运用的过程中如果拿 Idea 去开发,当选中一个 Rock 的工程之后,相应的安装包就会下载下来,不需要去进行下载。


2. 文献

https://reactjs.org/docs/hello-world.htm 是 React 的官网,在这个官网上面会有例如 Quick Start 的内容。

如果想了解有关 Idea 里面怎样开发 React 的内容,可以在 https://www.jetbrains.com/help/idea/react.html 里面找到有关的帮助文件。

之后在 https://my.oschina.net/korabear/blog/1815170 里面有一篇文章分析了一些有关 React 项目。也就是在 Idea 里面开发出来的项目,有关的文件结构的格式。


三、Hello world

1.基本形态

<!DOCTYPE html>

<html>

<head>

<title>hello React</title>

<meta charset=”utf-8”>

</head>

<body>

<div id=”app”>

<!--my app renders here -->

</div>

<script src=”react/build/react.js”></script>

<script src=”react/build/react-dom.js”></script>

<script>

ReactDOM.render(

React.DOM.h1(null,”Hello world!”),

Document.getElementByld(“app”)

);

</script>

</body>

</html>

以上是 React 在应用过程中最基本的一个样子。例如在 Index.html文件中,在 body 里面只有一个 div ,这个 div 就是将来所生成的 React 脚本中形成的内容。


2.制作过程

所书写的内容将来会在 ReactDOM.render 这个脚本中呈现出来,此脚本比较直观,当输入 h1 的时候,就会显示 hello world ,它会显示两个参数,第一个制作就是所画的内容,渲染的内容,呈现出的效果;第二个就是在 APP 上进行制作,也就是上节课当中讲到的 document.getElementByld ,在这个 ID 为此的 APP 的 DIV 里头,最后出现的页面,就是下面呈现出来的。他在 div 里面动态的插入了一个 H1 ,显示的是 hello word ,这便是 React 一个最基本的项目构成。

image.png


3. 默认创建

但是在之后看到的 react 当中,会发现默认创建的一个 react 工程跟上述步骤创建出来的存在一定的差异。

在默认创建的时候,会有一个 Object 和 Project 的区别,之后在选择静态网站的时候,如果选择 React APP ,就会帮助创建者创建一个工程,这个工程的结构里面实际上也会有一个 Index.html ,但是这个 html 只有一个,是 ID 为 root 的一个 div ,就是上述中实际的 body 未来也就是一个 div 。

在 index.js 里面,会要求在 root 这个元素中去绘制一个 APP 。 APP 也就是在创建好的 APP.js ,在自己写的内容的基础上,加上需要导入的其他东西,本质就是一个函数。


4. 存在不同

上述的工程,与所写出来的代码可能存在一定差异,但本质并无区别。就是将代码当中

<script>

ReactDOM.render(

React.DOM.h1(null,”Hello world!”),

Document.getElementByld(“app”)

);

这一部分单独拎出来放到一个脚本当中。这便是 React 最基本的一项显示, Hello World 就是这样来的,也就是通过脚本动态的去生成。

将此代码

<script>

ReactDOM.render(

React.DOM.h1(null,”Hello world!”),

Document.getElementByld(“app”)

);

动态的插入到 <div id=”app”>

<!--my app renders here --> 这部分。


四、Web storm

1.创建方法

了解wan创建 React 工程的方法,如果要用 Web storm 去进行,在目前的状态下,先写一个前端数据固定的一个版本是没有任何问题。但是相较于 Web storm ,用 Idea 会更方便,就像最初讲解的那样,即使有两个后台可以运行两个 Idea ,一个运行、一个工程进行通信。

创建完成之后就会形成下面的页面。在页面当中会嵌入脚本,脚本当中要求只在 ID 为Root 的节点上会有 APP 的根目录会有真正的代码,之后会返回 <h1>Hello World!</h1> 去运行,这是看到的这个

DEMO 。

如果下载这个工程,这一个 DEMO 工程里面会有很多代码,为了方便都会进行注视和标注,字母对应的右下角的位置出现 DEMO ,就会在相应的地方进行注视,就能达到最初的效果。


2.缺省代码

默认情况下实际上创建好的工程里面,这个 APP 里面是有运行的代码,如下图。image.png

通过上述代码的运行最终呈现出这样的效果。

image.png

那么呈现的效果从何而来,可以看到包括 Logo 在内等相关的东西都是在上述代码当中打包的东西。这便是缺省代码,标注之后的。代码已经运行,只要保存,相应的页面就会自动刷新,这便是我们看到的 Hello World 。


3. 工程结构

运行这种配置,相关配置在运行之后也要进行选中,要选择一个新的 npm ,想要代码运行,就要在 npm 中 package json 里面运行当前工程底下的 package json ,这个 package json 里面会有很多的东西,就让他去运行,可以运行 Start 这个脚本。在运行中会默认起一个 HTTP 的服务器,在3300至3万的端口,之后运用起来,会自动去读取当前这个工程里面的这个 Index. 页面,就会呈现出 Hello World 页面的效果。在查看源码的时候,里面的 Root 就是当前页面当中的,呈现出来的 Hello World 就是通过刚才的脚本自动生成进去的。还可以通过页面看到,有一个 static /js/bundic. 这个 bundic 就是所写的脚本最后都会进行编译的内容。那个结果就是将所写的内容,包括之前的相关内容都进行打包来进行一起呈现。


五、介绍 JSX

1. 考虑变量声明

如果要进行更复杂的操作,在这里面可以支持编写一些例如 javascript 和 XML 项目, HTML 混编的一种语言,就叫做 JSX ,即 javascript 的一个扩展。

例如 const element=<h1>Hello,world!</h1>  就是一个比较明显的例子,很明显前一部分是 javascript 的语法,后面一部分是 HR 的一个标签,就是让 element 等于后面一部分的内容。


2. 定义函数

下面就是一个定义函数,叫做 formatName 。参数就是 user ,在 user 当中就会有 first name 和 last name 。这两个通过一个空格进行连接作为这个函数的返回值。之后进行对 user  的定义,就是 harper ,另外一个 element ,如同前面的 jsx 一样,前面部分是纯粹的 javascript ,后面一部分就是 JSX 。则 element 就等于 h1 标签的 hello ,之后调用 formatName 函数,传递 user 这个参数进去之后返回的结果,引用的内容就是结果,最后就会呈现出 hello 。定义的就相当于 element ,为一个常量要调用 ReactDOM.render 的方法来进行运行,最后生成 Root 。image.png


3. 函数

当然代码与举例是有一定的区别,代码当中的 ID 是人为进行编写,会比较复杂,首先是定义 element ,之后定义所了解的函数和常数内容,应用完成之后 APP 当中换取一个标签,标签对应就是 APP 里面的函数 root 。在没有任何东西,进行注释之后报错打开,就是一个 return.element 。至于为什么会生成一个 APP ,是因为在整个JS 里面要导出 APP ,也就是说让其他 JS 文件可以运用到这个 APP 中,即这个相应的 APP 只是返回了一个 element 中。 element 的值就是 hello 经过调用得到的一个结果,那么经过这个地方得到的结果就是这个原因。经过保存之后看所显示的内容,相关内容就进行了改变。之后看源码当中所呈现的内容,会发现和刚刚所组装出来的内容,即 hello 加什么内容之后顿号。内容形成的原因是因为 hello 中间调用后面的顿号等三部分构成的,就会呈现最终的内容。


4.相关注意事项

上述内容就是 react 中最重要的,显示的就是相关 html 语法和 javascript 语法混编的内容,也就是 javascript 语法的一个扩展。其他部分就是纯粹的 javascript 脚本。

5.JSX本身内容

JSX 里面能看出本身就是一个表达式。在 <h1>hello,{formatName(user)}!</h1> 中就是混编的内容,即 html 的内容,引用的相关内容不是最初的 user ,在这个 if(user) 中, if(user) 的意思也就是 user 这个里面的内容是不存在的。如果存在,就会返回到 {formatName(user)}!</h1> 当中,之后得到 <h1>Hello,Stranger.</h1> 这个脚本。

如果没有提供 user 这个的对象,那么这个函数返回的值就是 hello 陌生人,那么这里面可以看到这个 user 的对象,就是被当成一个 if 标准判断的依据。之后是运用在 heml 和 javascript 混编在一起,反馈一个相应的结果,所以整个便是一个表达式,产生的一个结果返回。


6.指定属性

在 const element=<div tabIndex=“θ”></div> 中,后半部分是最基本的东西,在这里面本身可以带属性标签的属性,因为在 const element = <img src={user.avarUr1}></img> 中 src 本身表示里面的内容含义,来自于某一个对象的一个 avarUr1 属性。


7.其他属性

在 const element=<img src={user.avatarUr}/> 中,等号后面的部分跟上述部分一样可以带入使用,如果 element 本身是一个比较复杂的东西是可以用自身代替子标签的。例如当成为 <div> 之后,在里面可以带入 <h1>Hello!</h1> 和 <h2>Good to see you here.</h2> 。那么接下来有一个问题,所定义的东西到底是什么?应该怎么样去看待?其实在 react 里面做设计的时候,就要以面向对象的方式去考虑问题,也就是在页面上面,应该怎样去划分当前的页面里面的所有元素,这是最重要的部分,然后在所有的元素当中,去思考有没有相似的地方。如果有相似的东西,应该将其都转变为一个 component ,之后所有相似的东西都是一个实力。这就相当于定义了一个类。类当中有很多的对象,在这里提到的内容就应该是 h1 和 h2 合起来的 div 的问题,element 是 h1 还是 h2 ?取决于怎么看待这个 UI 页面, h1 光是 hello 这一部分是可以复用的吗?只要单独去处理了吗?还是说这两部分是密不可分的,如果两个都一起被复用取决于对象封装的力度是多少。因此对于语法的掌握是比较容易的,但是这种设计的方法,需要进行考虑,在很多的代码工程里面实践的时候去提高的。就比如一个人支持你在一个空间里面放桌子,那到底在一个位置可以放一张桌子,还是两张桌子。以此类推,相应的在代码当中的明确都也取决于对 UI的一个分析和工程经验,如果在这里单独使用是合理的,就单独使用,如果将二者结合可以发挥更大的效果,就进行组合使用,这便是设计依据。


8. JSX 表示对象

在JSX里面其实就是上述的案例,也就相当于 element 那个类的一个对象,就是通过 React.createElement()calls创建一个元素的话,实际上是创建了一个例子,就像在 const element=(<h1 className=”greeting”>Hello,world!</h1>) 中前面一部分等于后面一部分,实际上在背后就是调用了 React.createElement() 创建了一个对象进行展示,当然也可以显示的呈现出 React.createElement( 。而现在的 element 是有 ”h1”,{className;”greeting”} 的属性,但是很明显, h1 className 等于 greeting ,最后呈现出的 “Hello,world!”不会出错,但并不直观,要写成下面这样:

Const element={

Typr:”h1”,

Props;{

className;”greeting”,

Children;”Hello,world”

这便是在 element 当中最好写的一个——JSON , JSON的一个对象每一项都是一个键值对,这样便可以直观的说这个 element 是一个 h1 类型的,有两个属性,其中属性一是叫做  className greeting ,第二个属性是一个标签就是 h1 中间夹杂的 Hello,world ,这样写就会更明确,让别人一看就知道 element 到底是什么。

因此用 React.createElement 来创建实际上无论需不需要明确的写出来还是在代码当中用大括号或者直接写 h1 的内容都可以,但是一个本质是创建的 element 都是一个对象,这个对象将来可以去呈现在这个页面,而且人们可以对此进行操作,可以获取里面的属性值等。所以在 react 世界里面,其实更像一个后台的一个应用,一个面向对象的应用。因此在举例当中运用书的获取,为什么最后是用一个 class 而不是像书的历程里面给的是一个 Var ,在定义的时候,就是先去定义一个类,再从类里面去实例化一个对象出来。


六、渲染元素

1.含义

所谓的 element 就是对象,即在构建的这个应用里面最小的种种块儿构成的,单纯的可以理解为将页面切分成不同的模块,这些块儿与块儿之间可以有嵌套的关系,这些模块最后构成一个包含关系的层次关系,最后评估成一个完整的页面。那么 react element 的对象可能跟浏览器当中 DOM element 差不多,这个创建和回收的代价都比较小,也就是说创建一个对象,涉及到在内存里面要去寻找一块的空间,将构造器调用一下,把相应的对象的一些成员都要进行初始化,然后才将对象引用返回。

相比之下, react 的对象会显得成本更低,也就使通过 react 的对象来构建页面速度可能会更快,当然这只是在 DOM 当中的。 react 和 DOM 相比有一个特点,对于具体的实践逻辑可能会有些深奥,可以这样认为,整个页面如果运用 react 来创建可能会更好,因此在所了解到的 react 应用当中,整个在那个页面里面是一个单独的 <div> ,所有的东西都是在 DIV 当中进行勾画,如果说在 <body> 当中有两个以上的 div 实际上是不符合 react 的要求。因为只能认为实在同一个 div 里头,里面的 body 页面是一个完整的,内容由其控制但整个全部被 react 接管。


2.渲染元素到 DOM 中

在 <div id=”root”></div> 里面只有一个 div ,可以替换,不一定非要用 root ,之后会被 react 接管在里面去呈现,因此在 ReactDOM.render(element,document.getElementById(“root”)) 里面很重要的就是 react 对象的选择方法,有两个参数,其中的参数也比较容易进行理解。第一个就是需要渲染什么,第二个就是往何处去渲染,任何一个 react 的应用大概都是以这样的方式起头的,也就使整个页面只有一个 div ,将内容插入其中,然后补充里面剩下的内容,就完成了。


3.更新被渲染的元素

假设想进行更复杂一点的。就是如果在页面上呈现出一个东西,例如钟表, clock 这个里面的内容如果想进行变化应该如何进行,下面是相应的代码。

Function tick(){}

Const element=(

<div>

<h1>Hello,worle!</h1>

<h2>It is {new Date().tolocaleTimeString()}.</h2>

<div>

);

ReactDOM.render(element,document.getElementById(“root”));

;

setInterval(tick,1000);

定义一个函数 tick 还有 element , element 里面会显示一部分,在 H2 当中的内容是在取当前的时间进行绘制,然后设置一个定时任务,其中的单位是毫秒,每间隔一秒就调用 tick 去读取当前的时间,之后每次要进行就可以去 render ,然后钟表当中时间就会进行变化。在 app 当中定义一个常量,将代码定义清楚,在需要的时候运行。保存相关数据之后,看所进行的页面,会发现时间不会更改的问题,原因是什么?

image.png

可能因为没有重启,在将页面进行刷新之后也是看到对数据的读取也只进行一次时间就是结束了。究其原因还是需要去看代码,代码是一个常量,一次定义好的内容,之后每次运行就进行绘制,每隔一秒钟就需要变化。当然其中的部分不属于刚才的 app ,是 app 的一部分,之后再次尝试运行,就会发现时间进行了变化。

因此定时要打开,再打开之后还需要“下午时间”在不断进行变化,这个的不断变化意味着在当前页面当中只有这一部分在进行更新。前面的 it is hello world 这些内容都没有进行更新,只有闪烁的内容在更新。

实际上对于 react 来说,对然在这里要运行一个 element ,而 element 确实也是定义当中的一个 div ,里面有 hello world ,有 it is 这些是不变的,每一次固定的内容,只有时间是发生变化的,在 render 的时候可以想象的是应该进行整体的呈现,实际上只是将里面的内容进行替换。

这是一个特性,在 react 运行的过程中,会去提供当前页面变化的部分内容,在整个页面当中 hello word 和 it is 是固定的内容,只有时间是变化的,因此每次只有时间在进行闪烁,代表时间被更新掉了,也就使只更新希望被更新掉的内容,没有被更新过的内容,是不会再次进行刷新的,因此效率非常高。


4. 更新 React 认为重要的内容

image.png

以上是之前运行过的一个界面,和上面的内容大同小异,反复观看就只有标红的内容在更新,所以 react.dom 在进行 render 的时候,只有这部分进行更新,其他部分是没有进行更新的,也就使更新必要更新的内容,自然也就节省了相关的计算资源。


七、组件和 Props

1.含义

之所以要将整个页面划分成很多不同的构建,就是因为想要去复用这些构建,而且这些构建彼此之间是可以相互独立的,一个复杂的应用,大的页面,里头有很多不同的模块,那每一个模块都可以独立成一个  component 。之后将他们都拼起来构成UI,因此要想进行复用,在复用之前的含义是如同一个类,如果复印的话,就意味着在这些标签和区域里面,这两个区域是同一种空间,只是现实的内容不同。例如一个钟表显示的是美国的,一个显示的是欧洲的,那么二者实际上大部分的代码是一样的只是那个国家的名字不同,因此可以将其当成一个变量传递给钟表,让两个钟表之间去复用这个构建。不同国家就像参数一样进行传递,也就是一个构建的输入,输入可以用 props 来进行封装,传递东西。那么整个这个构建,会接受 props 的东西,其中的东西就相当于如果将这个类想象成一个类的话,其构造器函数就可以进行传递。然后在 react 当中这个类可以返回一个具体的对象,这个对象寻找一个 element 。


2.函数和类组件

image.png

如果按照上述的想法,需要按照类的方式去定义一个构建。这个构建可以接受参数,这个参数是外界传递的,参数当中包含了很多东西,实际上里面是一个参数以及一个键值对。选取 name 里面的对象参数的值,之后就会显示 hello,props.name 。那么之前 component 看起来更像是一个类,如果按照类的方式进行编写,可能会更加显得亲切一点,也就更加接近于 Java 编程语言.写一个类,会扩展至 react.components ,之后里面的 render 方法就是会渲染这个绘制的方法要返回一个结果。这个时候会出现一个问题,为什么种种方法不想前边的方法能显示的看到 props ,其实是默认了创建的过程中 props 就被传过,传给可以得到里面的内容就可以。写成类就会显得看起来更符合面向对象的一个关系,当然两个是完全一样的等价,写成哪个都可以,最初写出来的代码就是方程,之后在数据浏览的例子里面,就写成了 class 。


3.渲染一个组件

image.png

如何进行复用。刚才写出来不要卡,现在在创建对象 welcome ,无论是前面用函数方式写的还是用类方式写的,这种构建都可以被外面免去当成一个标签进行使用,就像当初需要创建 app 一样,在index JS里面。而这里的意思是需要去调用 welcome 去生成一个新的 element,其中这个 welcome 是由一个新的属性,因此在这里面会写到 name=Sara 。在这样写完之后,在props 当中,其相关的 name 属性都被封装了进去,就等于 Sara 。下部分的也是相同的被封装之后,直接传递,当前的 welcome 在里面可以直接去获取。其中的作用是在定义了一个 welcome 之后可以说需要在某一个地方去创建一个 element ,就跟之前看到的很类似,唯一不同之处在于多了一个自定义标签。也就是需要从自定义的某种类当中,在更宽泛的类底下,一个component当标签去使用,然后后面就可以传递参数,可以利用参数去创建不同的实例出来,和之前的 hello world 没有什么差异。


4.组成部分

image.png

如果另外定义 component 的目的是为了去服用,如果当页面里面只有一个 welcome 的时候,做这样的事情再去复用就显得意义不是特别大,还不如不去定义直接写出来。

但是在这里的一个应用中也就而已看出实际上从 welcome 里面创建了三个不同的元素,也就是从一个类当中创建了三个不同内容的对象,之后将其显示到这里就可以看到将 welcome 定义成一个 hello 什么,之后将三个拼起来,又用函数的方式定义一个新的 app ,然后画一个 app 。

这便是所谓的类里面可以套用其他小的类,其他小的类继续套用,以此类推。

实际上在整个页面当中,其实是画了一个 app的构建,这个构建里面包含了三个 welcome 构建嵌到一个 div 的空间当中,然后每一个 welcome 又是一个 element 对象,所以例子即使简单,但是也至少说明了一点的那,一个比较大的复杂的页面,将如何通过小的元素不断地聚集,产生了最重大的页面。


5.举例

image.png

接下来的内容就是上述内容,之后 welcome 需要进行定义,这里全部是按照函数的方式来进行定义,就如图中显示的一样,之后进行刷新,刷新之后在观察,观察生成之后最终给前台的页面,可以看到是三个 h1 的。也就是会将后台的内容全部处理完生成一个静态的页面发回到前端,前端看到这样的东西,就是浏览器当中现实的东西之后,里面有三个已经生成好的内容。

image.png

在此例子当中一个 app 包含了三个 welcome,三个 welcome 又每一个都是 welcome 的对象,也就说明了以一个大的页面,可以不断地去分解,分解成很多小的部分,小部分继续分解,分解到最后可能不能分解为止,或者说认为其复用到此为止,以下不会再有更细的力度的分解的必要,所以整个页面就会这样构成。


6.提取部分

假如要在网上进行发送帖子,发帖的时候,如果说用 comment 这样的一个 component 。就会有一些 props 传递过来,也就是每创建一个 comment 这个内容就会进来,进来以后会有作者的头像、姓名、作者的孩子姓名,之后在 text 当中真正会显示呈现的内容,之后有一个日期,都是通过 props 传递进来,也就是 props 在那里传递进来的里面包含了一个 author 对象,一个 text 。其中 author 里面又有头像在哪里,名字是什么,之后就会返回一个结果,返回的结果仍然是一个 div 的东西,里面又会包含三个 div ,其中又包含了一个小的 div 和一张图片。总的来说,在显示一个用户信息里面的头像,名字,和重复名字,就形成了这样的结果。

image.png

从面向对象的角度去设计的话,很自然地会想到,既然这是 author ,传递中清楚, author 有 avatarUr 、 name ,因此将其拿出来,,这样的话其中的 user、 avatarUr  和 name 组成一个新的 component 。然后未来这个里面就变成进来以后 user 是嵌了一个 avatarUr  ,之后其他地方不变,因为 user={props.author} 会在很多地方被频繁的使用,将其抽取出来,变成这样一个内容,就是不断的在设计一个页面的时候,根据页面的内容,根据所需要的复用的情况,然后不断地抽象里面有哪些 component ,让代码组织起来显得更加的合理。这便是在应用中功能虽然是一样的,但是也存在一定区别。在前面的举例当中可以看到如果需要将代码写完整会比较复杂,然后呈现出来的内容会显示头像是谁,显示的内容和日期。


7.构成

在构成的时候,Format date 是为了把日期转成符合当前显示习惯的一个字符串,到底是年月日,还是日月年,还是月日年。之后看到 common  在里面, common 是一个div,里面有三个,然后第一个 user if 这个地方看到有 image ,如果图像当中没有需要显示名字,然后再显示,如果其中图像需要先显示图像,然后显示名字,这是结果。之后创建了一个新的 comment ,想要进行显示,取当前日期,也就是2012年3月12号,这是真正书写的一条 comment ,然后底下是 author ,有 name 和 avatarUr 这些远程的图片,然后在底下的 render 这个地方,去把 comment 画出来, comment 画出来的时候要注意的是带了三个参数,需要把这三个参数组装到 props 里面。当参数传递,就在 comment 这三个键值对,键值对来自于常量里面的值。

最后绘制到 root 这个地方,这就是一个例子将功能实现,但是结构化不是特别好,因为可以被提取出来专门作为一个 comment 很抽象的东西,没有抽象出来。

之后了解另外一个例子,这个例子就比上一个的要进步一点,其他的地方没有什么变化, comment 常量没有变化,然后 render 还是需要画一个 comment ,把这三个常量的值赋予进行画,然后上面 comment变得简单,底下的两部分 Text 和 data ,仍然没有变,就是上面的变简单,上面是要成为 render ,需要绘制一个 User.info 。 之后了解 user info ,是新定义的内容, User.info 本身也是一个标签,有一个输入参数是peops传递的,也就是说 comment 将传递的参数里面的 author 当成新的输入参数传递给  User.info ,之后就得到了 User.info ,也就是 author 得到了 User.info 的内容。 之后将 user 里面的内容提取出来进行操作。 user当中会有 name ,又会有头像的 URL ,因此里面需要有 avatarUr ,有名字的内容,之后 avatarUr ,又是新定义的一个标签,将 avatarUr , User.info 所拥有的user 属性原封不动的进行传递,然后进行封装。

封装完成之后,从用户的角度看,刷新之后没有什么变化,但是仔细对比会发现按照之前封装的 User.info 和 avatarUr 的角度,代码多了两个标签。即在未来其他地方运用到 User.info ,或者单独使用 avatarUr 时就可以直接运用,因此这时的代码费用成本就会升高。另外实际上在 IDEA 里有一个很强的功能,有两个版本的 product 例子,二者有很多代码是一样的,只不过有的里面增加了一些代码,有重复代码,即写代码的时候,如果有警告这种问题,不是红线就是黄线,执行起来没有任何问题,但至少说明一点,一定是代码写的有问题,重复代码要么抽象成方法,要么抽象成类,而不是重复着,所以会报错,也就是说将来写代码应该尽量的可以服用。凡是需要复用的地方就将其复用,不要出现重复代码。

其实无论是抽象 avatarUr ,还是底下又抽象出了一个更复杂的User.info ,都是从复用的角度来考虑问题。也就是说未来user info或者单独的 avatarUr ,可能会在除了comment ,比如说用户管理里面会出现。所以将其提取出来变成一个 common ,变成一个 component 。所以在讨论一个问题,就是页面还是之前所描述的,既然这个页面元素是可以拆分成不同的部分,不同部分到底是怎么抽象 component ?一个基本的依据就是代码将来要不要服用,如果只出现一次,编写的意义并不是很大,如果出现很多次,应该抽象成一个一个 component 即所谓的一个类,然后创建不同的元素,组成不同的props,创建不同的显示内容,不同或者其他不同的这样的对象,去组成整个页面。

image.png

刚才的描述就是经过整合之后,代码费用程度会变高。


8.Props是只读的

Component 要注意刚才传递的时候再创建一个很暴露 element 的时候,传递的 props 这个东西就是相当于一个参数一样,那么在 javascript 里面,也就是在 react 这个框架里面,希望写的函数都是一些这种叫做 pure 的函数,如果了解所谓的函数式编程的话,函数有什么特点,就像在高中时候学的 Y=F(X) . Y=F(X) 的一个特点是,无论怎么计算,在这个函数题里,X的值是不会发生变化,这才叫真正的数学意义上的一个纯粹的函数。从这个角度来说,创建一个 element 的时候,传递进来的参数就相当于这里的 X 这个自变量。而真正画出来那个 element 就是这个 y 的因变量,那么自变量是不应该发生变化,所以叫 read -only ,是一个只读的。

image.png

属性是只读的,怎么去理解呢?比如说在这个 sum (a,B) 这个函数里, A 和 B 的值没有发生变化,所以是存粹的,但是底下这个是一个取钱的一个函数,说要从这个账户里面取掉这么多钱,于是就会说,这个人的总额要减去 amount 。在这个例子里面, account 的值发生了变化,也就是说自变量值发生了变化,那在这里面,在 react 的眼里,这就不是一个纯的函数。 react 里面就强调所有的 component 必须像纯粹的函数一样。因为 component 有两种写法,一种是用 class 来写,一种是用 function 来写。无论用哪一种写,都应该看起来像一个纯的函数,也就是说传递进来的这个参数不能发生变化,不能去改写,比如说不能去尝试着要把某一个 name 赋个值等于什么什么,这是不允许的。所以仔细去看前面的代码,在这里是在直接使用。没有一个地方再说进行复制。因为不能改这是一个特点,就是值是只读的,不能修改,那不能修改的话,其实限制很大,比如说clock这个例子,在创建这个表,就给一个时间。拿到这个时间之后就将时间显示出来。之后又因为 props 不能改,所以每隔一秒就需要重复调换 tick ,把整个 clock 重绘一遍。那如果值能改,直接把值改掉,再去重复一遍,这就比较好,为什么呢?

image.png

仔细看这一个 clock ,这个 clock 有一个严重的问题,其实功能只是在显示需要显示的那个时间,至于多长时间走一次,一秒钟走一次,只要绘制出来,这件事情都在这一个 clock 之外,也就是说这个 clock 其实根本就不是一个 clock 。只是显示了一段时间,其他的内容都在这之外,另外再用这个 clock 的时候,如果 clock 想被服用,就非常的麻烦,要补底下代码。这不是需要的,需要的是一个在某个地方绘制一个 clock ,然后就开始自动往前走,至于前面这个什么,要传递给一个时间,然后每隔一秒都要去重新执行 tick 函数,给足时间进行重绘,这件事情就不要进行。直接就像之前说的写一个 clock ,之后就自动进行运行。第一不需要告诉时间是什么,就按照当前的时间进行变化,第二不用控制,一秒钟倒掉 tick ,第三不用控制,每一次调的时候要去绘制,直接这样,这才叫真正的一个 clock 。也就是说把绘制的逻辑,还有每一秒要更新,全部自动控制。要想实现这个目标,按照刚才的这个写法是不行的,原因是因为在 clock 里面,传递 props , props 又是一个只读的,缺乏去修改的时间,只能靠每一次重绘这个 clock ,实际上就相当于每一次都产生了一个新的对象,然后去把里面的内容改掉,那这样的话会非常的累,所以希望是用这种方法来做。


八、状态和生命周期

1.关键要求

那这种方法用 props 达不到怎么办呢?就在 react 里面就有一个叫state的东西。 State 是可以修改, State 相当于什么呢?也是相当于这个 clock 的一个属性,只不过在上面看到 props 实际上是外面传递的一个东西。可以在 clock 里面去操作的。那么 STATE 是什么? STATE 可以认为是在整个 clock 里面的不断地传递是个私有东西。那么还有一个特点就是说 States 是指跟这个具体的元素相关,比如说创建 clock ,下面再创建 clock ,这两个 clock 可以有不同的 STATE ,就是比如说都有一个状态叫做时间,但是时间可以不一样,也就是说从类的角度来说叫做实例属性。就是每一个实例之间都可以不一样就比如说两个不同的人的名字是不同的,因为两个人是不同的人。


2.将函数转化为类

把刚才这个 clock 能实现的功能但不是特别好的,进行改写。就是要定一个 clock 这个类,用 class 方式来写,之后改写里面的内容。

先把刚才的这个标签,给改写成类,然后在类里面去改写内容,达到目的。

先把刚才攻击改写成类,就变成了这样,传递进来的 props 里面的那个 data ,然后转成当前的时间,这是第一步改写好了,然后现在就要改一下时间,时间不能是 props ,时间应该是从 states 来。 States 就是当前的 clock 对象未来会具有的一个状态。假设这个状态已经有了,每次就在显示这个状态里面的那个时间,然后转成时间出来,现在要解决的状态从哪儿来?状态从当前的构造器再进行构造的时候来。那就设置状态,这个状态和 props 一样,里面可能有很多个键值,当然也有可能外面在创建 class ,会给 props ,但是这 props 现在已经没有意义了,不会从里面堵时间,所以调一下 super, 之后就顺其自然。

之后用 state 来控制,所以在构造器里,就是在每创建一个 clock ,在构造器里去把状态进行赋值,所赋的值就是 date ,等于当前的时间。然后绘制,这个 state 是从上面的内容来的。那现在有了这个初始状态,还要考虑不断的去更新状态,所以之后就需要 clock ,render 就在里面就直接用一个 clock 这个标签,然后下面就要去考虑那个 stated 该怎么去处理。 在 state 进行处理的时候,需要进行考虑,这个 state 是一个实例变量,那么这个实例变量如果在对象移除之后可能要给删除掉,当然这件事情会自动做。

那这个实例变量要求是每隔一秒钟要改变值,问题是需要有定时器每隔一秒钟去把这个状态给更新一下,那这个定时器在什么时候开始起起作用,然后这个定时器不能一直无休止的运行,即使最后对象没有还在运行就有点浪费资源,应该在当前这个 clock 如果被删掉,比如说页面关掉这个 clock 应该终止掉,那什么时候去设一个定时器,什么时候去删除这个定时器。可以用这样两个方法,这两个叫做生命周期的高参数或者回调函数,就是在做这个设计的时候,一开始要创建一个对象的时候,你比如说用 new 关键字创建对象的时候,就调用了,然后要通过 delete 一个对象,会掉那个吸够气。作用是当对象被创建出来之后,在这个对象被销毁之前想做些什么,这就是跟生命周期相关的函数,那么构造其实在构造的时候要做什么。

那这个对象有了,但是这个对象真正被绘制出来的时候,还想做一些什么东西就在 componentDid Mount() 里面去做,也就是说构造及时把这个对象构造出来,这个方法是在页面上呈现出来之后,要做什么?那与之相反,就是这个对象如果想要删除,在删除之前要干什么?可以看到两个方法的名字不一样,一个是 Did Mount ,就说已经绘制出放到哪儿,然后要做什么,这个 will 很棒,就是说将要被删除的时候,要做什么?注意这两个方法只做一次,就是说这个元素第一次被绘制出来,放到页面上的时候,那一刻要做什么。 will 是说马上就要在内存里面被移除掉之后做什么,所以叫做生命周期函数,也就是在出生以后要干什么,在死亡之前要做什么。

那么这两个地方就是放定时器的地方,所以现在要放定时器,在这个对象被绘制出来放在页面上之后,马上要干的一件事情就是设置一下定时器,定时器每一秒钟执行一次调用当前的 tick 函数,然后给定时器进行命名,就叫 timerID  然后在元素将要被删除之前,去调了一下 clear ,要删哪个定时器就像刚才创建的这个 time ID 。

所以现在就有了定时器,有了定时器之后还不够完善,定时器只是一秒动作了一下,需要 tick 方法来把每次都要绘制的 state.date 中的 date 值进行修改,所以在后面会有 tick 方法, tick 方法就会去掉 setState 的方法,把 data 替换成最新的时间。在这里会出现两个问题,第一个为什么不写 this.state.date=new date() ,而是一定要 state.date ,方法来事件,因为在 react 当中 state.date 会触发,一旦状态发生变化,就会触发 render ,之后就会进行重新绘制,之后就会将写出来的表进行刷新;第二是 this.state.date=new date() 方法不能保证 date 立马被更新掉,有一定的延迟性。因此 setState 是立马进行,而另一项不是立即进行。

也就是告诉 react 将 state.date 进行更新,然后回复说知道,以后会看,没有及时性。只有在构造器里面可以运用,其他不太可行。


3.举例

例子当中每次都重新绘制一个 clock ,虽然不是太好。

image.png

以上就是另外的例子,比较完整。在马上要进行的事情上有一个定时器,在构建被删除之前,将其删掉,免得定时器不在了,还有存货。之后的 tick 就是每间隔一秒钟将 date 的状态刷新成最新的状态。当前的 clock 的实现是比较好的。

相关文章
|
1月前
|
XML 前端开发 JavaScript
react学习笔记一:入门级小白到脚手架(create-react-app)开发项目
这篇文章是React的学习笔记,覆盖了从React的基础用法到高级特性,包括组件化、状态管理、生命周期、虚拟DOM等主题,适合React初学者参考。
92 0
react学习笔记一:入门级小白到脚手架(create-react-app)开发项目
|
5月前
|
移动开发 前端开发 Java
技术笔记:ReactNative学习笔记(一)————(RN)快速入门
技术笔记:ReactNative学习笔记(一)————(RN)快速入门
65 0
|
Web App开发 前端开发 JavaScript
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
131 0
|
前端开发 API
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-react-redux的工作流程
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-react-redux的工作流程
82 0
|
6月前
|
前端开发
React学习笔记(一)
React学习笔记(一)
|
6月前
|
前端开发
React学习笔记
React学习笔记
|
6月前
|
前端开发 JavaScript
《Webpack5 核心原理与应用实践》学习笔记-> React全栈环境
《Webpack5 核心原理与应用实践》学习笔记-> React全栈环境
74 0
|
JavaScript 前端开发 调度
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber和虚拟dom关系
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber和虚拟dom关系
82 0
|
前端开发
前端学习笔记202307学习笔记第六十二天-react原理之1
前端学习笔记202307学习笔记第六十二天-react原理之1
65 0
|
前端开发
前端学习笔记202307学习笔记第六十一天-react知识点串讲之6
前端学习笔记202307学习笔记第六十一天-react知识点串讲之6
68 0