文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

(React 框架)React技术

2023-01-30 22:44

关注

1、简介  

  React 是Facebook 开发并开源的前端框架

  当时他们的团队在市面上没找到合适的MVC 框架,就自己写一个 JS 框架,用来架设 instagram(图片分享社交网路),2013年开源

  React 解决的是前端MVC 框架中的view 视图层的问题。

2、Virual DOM

  DOM(文档对象模型Document Object Model)

   

    

  将网页内所有内容映射到一颗树形结构的层级对象模型上,浏览器提供对DOM的支持,用户可以是用脚本调用DOM API 来动态的修改DOM 结点,从而达到修改网页的目的,这种修改是浏览器中完成的,浏览器会根据DOM 的改变重绘 改变DOM 结点部分。

  修改DOM 重新渲染代价太高,前端框架为了提高效率,尽量减少DOM 的重绘,提出了Virtual DOM,所有的修改都是在现在的Cirtual DOM 上完成的,通过比较算法,找出浏览器DOM 之间的差异,使用这个差操作DOM,浏览器只需要渲染这部分变化就行了

  React 实现了DOM Diff 算法,可以高效的对比Virtual DOM 和DOM 之间的差异。

3、支持JSX 语法

  jsx 是 一种JavaScript 和XML 混写的语法,是JavaScript的扩展

  XML 被设计为传输和存储数据,其焦点是数据的内容。 HTML 被设计用来显示数据,其焦点是数据的外观

  

4、测试程序 

  修改 /src/index.js: 

    

  修改 根目录下的 index.html:在html文件中,提供一个div标签,同时提供id ,使得react可以通过id找到

     

  启动 npm start 后

       

    

  程序解释

    

    import React from "react";  导入 react 模块

    import ReactDom  from "react-dom";导入react 的DOM 模块

    class Root extends React.Component :组件类定义,从React.Component 类上继承,这个类生成JSXElement对象即React元素。

    render()渲染函数,返回组件中渲染的内容,注意,只能返回唯一一个顶级元素回去            

    ReactDom.render(<Root/>, document.getElementById("root")):第一个参数是JSXElement对象,第二个是DOM的Element元素,将React元素添加到DOM的Element 元素中并渲染。 也可以使用name,如果Element元素的属性定义了name,document.getElementsByName("newroot")

    (不推荐使用)还可以使用React.createElement创建react元素,第一参数是react组件或者一个HTML的标签明后才能(如:div,span) 

     

  增加一个子元素: (这就是SPA网页,单页应用,普通的爬虫就只能爬基本页面了,因为此时,css和js分割开了) 图二是 DOM数,虚拟DOM 是react的事   

       

    注意:

    1. React组件的render函数return ,只能是一个顶级元素
    2. JSX语法是XML,要求所有元素必须闭合,注意<br />

     JSX 规范:

      • 约定标签中首字符小写就是html标记,首字母大写就是组件
      • 要求严格的HTML标记,要求所有标签都必须是闭合的,br也应该写成<br /> ,/ 前留一个空格
      • 单行省略小括号,多行使用小括号
      • 元素有嵌套,建议多行,注意缩进
      • JSX表达式:表达式使用{ } 括起来,如果大括号内使用了引号,会当做字符串处理,例如 <div>{'2>1?true:fase'}</div>  

         

5、组件状态 state 

  每一个 React组件 都有一个状态属性 state,它是一个JavaScript对象,可以为他定义属性来保存值

  如果状态变化了,会触发UI 的重新渲染,使用setState()方法可以修改stste值

  注意:state是每个组件自己内部使用的,是组件自己的属性

  依然修改/src/index.js

    

    解决方式1:

        

       可以使用延时函数,setTimeout(()=> this.setState({ p1: ' jerry' }), 3000)  是一个异步函数

      但是 不要这样使用,把setState放在别的地方      

      setInterval() 每几秒,执行一次,而 setTimeout 多少秒后,执行一次

  复杂状态的例子  

    

    浏览器结果:

       ========》点击后

 

    

              div的id 是t1 ,鼠标按下事件捆绑了一个函数,只要鼠标按下就出触发调用 getEventTrigger 函数,浏览器会送给他一个参数 event, event是事件对象,当事件触发时,event 包含触发这个时间的对象

 

  HTML DOM的JavaScript 事件

      

      

    使用React 实现上面的传统的HTML

      

      

 

    分析:

      Toggle类

        它有自己的state属性

        当render完成后,网页上有一个div标签,div标签对象捆绑了一个click 时间的处理函数,div标签内有文本内容

        如果通过点击左键,即触发了一个click方法关联的handleClick 函数,在这个函数里将状态改变

        状态值state,的改变 将引发render重绘

        如果组件自己的state变了,只会触发自己的render方法重绘。  

    注意:

      {this.handleClick.bind(this)} 不能外加括号

      this.handleClick.bind(this) 一定要绑定this,否则当触发捆绑的函数时,this是函数执行的上下文决定的,this已经不是触发事件的对象了。

      console.log(event.target.id) 取回的产生的对象的id,但是这不是我们封装的组件对象,所以

      console.log(event.target ===this) 是false,所以这里一定要使用this,而这个this是通过绑定来的

      event.target 就是生成的一个块 <div>-----</div>

    React中的事件:

      使用小驼峰

      使用JSX表达式,表达式中指定事件处理函数

      不能使用return false 如果要组织事件默认行为,使用event。preventDefault()  

  

6、属性props:

  props 就是组件的属性properties。

  把React组件当作标签使用,可以为其增加属性,如下:

    <Toggle name="school" parent={this} />

  为上面的Toggle 元素增加属性:

    1. name="school" ,这个属性 会作为一个单一的对象传递给组件,加入到组件的porps 属性中
    2. parent = {this} 注意这个this是在Root 元素中,指的是Root组件本身
    3. 在Root中为使用JSX 语法为Toggle 增加子元素,这些子元素也会被加入到Toggle组件的props.childern中

      

      尝试修改props 的属性值,会抛出 TypeError:cannot assign to read only property “name” of object # <Object>异常

        应该说, state是私有 private 的属于组件自己的属性,组件外无法直接访问,可以修改state但是建议使用setState方法

        props是公有public属性组件外也可以访问,但是只读。

      

7、构造器constructor:

  使用ES 6 的构造器,要提供一个参数props, 并把这个参数使用super传递给父类

    

  

8、组件的生命周期:

  组件的生命周期可分为三个状态

    • Mounting :已 插入真实的DOM
    • Updating:正在被重新渲染
    • Unmounting:已移出真实的DOM

  组件的生命周期状态,说明在不同时机访问 组件,组件正在处于生命周期的不同转台上

  在不同的生命周期状态访问,就产生不同的方法。

    • 装载组件触发
      • componentWillMOunt 在渲染前调用, 在客户端---也在服务端。只会在装载之前调用一次。
      • componentDidMount 在第一次渲染后调用,只在客户端,之后组件已经生成了对应的DOM 结构可以通过this.getDOMNode()来进行访问,如果你想和其他JS 框架一起使用,可以在这个方法中调用setTimeout,setInterval或者发送AJAX 请求等操作(防止异步操作阻塞UI),只在装载完成后调用一次,在render之后
    • 更新组件触发,这些方法不会再首次render组件的周期调用
      • componentWillReceiveProps(nextProps)在组件接收到一个新的prop的时候,调用,这个方法在初始化render时不会被调用
      • shouldComponentUpdate(nextProps,nextState)返回一个布尔值,组件接收到新的props或者state时被调用,在初始化时或者使用forceUpdate时不会被调用
        • 可以在你确认不需要更新组件时 使用
        • 如果设置为false,就是不允许更新组件,那么componentWillUpdate,componentDidupdate不会执行  
      • componentWillUpdate(nextProps, nextState) 在组件接收到新的props或者state但还没有render时被调用,在初始化时不会被调用
      • componentDidUpdate(prevProps,prevState)在组件完成更新后立即被调用,在初始化时不会被调用        
    • 卸载组件触发
      • componentWillUnmount 在组件从DOM中移除的时候,立即被调用

          

    有图可知:

      constructor 构造器是最早执行的函数

      触发更新生命周期函数,需要更新 state 或 props

      因此,重写编写 /scr/index.js

      构造两个组件,在子组件SUb中,加入所有生命周期函数

    测试装载,卸载组件的生命周期函数。    

 1 import React from 'react';
 2 import ReactDom from 'react-dom';
 3 
 4 
 5 class Sub extends React.Component {
 6   constructor (props){
 7     console.log("sub constructor")
 8     super(props);
 9     this.state = {count:0};
10   }
11   handleClick(event) {
12     this.setState({count:this.state.count + 1});
13   }
14   render() {
15     console.log('sub render');
16     return (
17       <div id="sub" onClick={this.handleClick.bind(this)}>
18         Sub's count = {this.state.count}
19       </div>
20     );
21   }
22 
23   componentWillMount() {
24     console.log('sub componentwillmont')
25   }
26 
27   componentDidMount() {
28     console.log('sub componentdidmount')
29   }
30   componentWillUnmount(){
31     console.log('sub componentdidunmount')
32   }
33 
34 
35 }
36 
37 
38 class Root extends React.Component{
39   constructor (props) {
40     console.log("root constructor")
41     super(props);
42     this.state = {};
43 
44   }
45   render (){
46     return(
47      <div>
48       <Sub />
49     </div>
50     )
51   }
52 }
53 
54 ReactDom.render(<Root/>, document.getElementById("newroot"));

 

   结果:

         

 

     增加,更新组件函数:

     演示 props的改变,为Root增加一个click事件处理函数 

 1 import React from 'react';
 2 import ReactDom from 'react-dom';
 3 import { runInAction } from 'mobx';
 4 
 5 
 6 class Sub extends React.Component {
 7   constructor (props){
 8     console.log("sub constructor")
 9     super(props);
10     this.state = {count:0};
11   }
12   handleClick(event) {
13     this.setState({count:this.state.count + 1});
14   }
15   render() {
16     console.log('sub render');
17     return (
18       <div style={{height:200 + "px", color:'red', backgroundColor:"#aaffff"}}>
19         <a id='sub' onClick={this.handleClick.bind(this)}>
20           sub'x count = {this.state.cont}
21         </a>
22       </div>
23     );
24   }
25 
26   componentWillMount() {
27     //constructor 之后,第一次render之前
28     console.log('sub componentwillmont')
29   }
30 
31   componentDidMount() {
32     // 第一次render之前
33     console.log('sub componentdidmount')
34   }
35   componentWillUnmount(){
36     //清理工作
37     console.log('sub componentdidunmount')
38   }
39 
40   componentWillReceiveProps(nexProps) {
41     // props更新时,街道新的props,交给shouldComponentUpdate
42     // props组件内只读,只能从外部改变
43     console.log(this.props)
44     console.log(nexProps)
45     console.log('sub com---receiveProps', this.state.count)
46   }
47 
48   shouldComponentUpdate(nexProps, nextState) {
49     // 是否组件更新,props 或state 方式改变,返回布尔值,true才会更新
50     console.log('sub shuold--------', this.state.count, nextState)
51     return true
52 
53   }
54 
55   componentWillUpdate(nexProps, nextState) {
56     //同意更新后,真正更新前,之后调用rener
57     console.log('will update', this.state.count, nextState)
58   }
59 
60   componentDidUpdate(prevProps, prevState){
61     //同意更新后,真正更新后,在render在之后调用
62     console.log('did Update', this.state.count, prevState)
63   }
64 
65 }
66 
67 
68 class Root extends React.Component{
69   constructor (props) {
70     console.log("root constructor")
71     super(props);
72     this.state = {flag:true, name:'root'};
73 
74   }
75   handleClick(event){
76     this.setState({
77       flag:!this.state.flag,
78       name:this.state.flag ? this.state.name.toLowerCase() : this.state.name.toUpperCase()
79     })
80   }
81   render (){
82     return(
83      <div id='t1' onClick={this.handleClick.bind(this)}>
84       my name is {this.state.name}
85       <Sub /> {}
86     </div>
87     )
88   }
89 }
90 
91 ReactDom.render(<Root/>, document.getElementById("newroot"));

 

   componentWillMount 第一次装载,在首次render之前,例如控制state,props

  conpinentDidMount 第一次装载结束,在首次render之后,

   

 

 

 

 

 

 

 

注:++ 原位置自动加1 ,+= 是调到栈里,加1 再返回

 

 

 

 10、无状态组件

   React从15.0 开始支持无状态组件,定义如下:

    

   无状态组件,也叫函数式组件

   开发中,很多情况下,组件其实很简单,不需要state状态,也不需要使用生命周期函数,无状态组件很好的满足了需要

  无状态组件函数应该提供一个参数props,返回一个React元素

  无状态组件函数本身就是 render函数

   改写上面的代码:箭头函数

    

 

 11、高阶组件

   

   如果要在上例的Root组件进行增强怎么办,例如将Root 组件的div 外部在加入其它的 div

  

  简化Wrapper   

     

 1 import React from 'react';
 2 import ReactDom from 'react-dom';
 3 // let Wrapper = function (Component, props) {
 4 //   return (
 5 //     <div>
 6 //       {props.schoolName}
 7 //       <hr />
 8 //       <Component />
 9 //     </div>
10 //   )
11 // }
12 // 柯里化
13 let Wrapper = function (Component) {
14   function _wrapper(props) {
15     return (
16       <div>
17         {props.schoolName}
18         <hr />
19         <Component />
20       </div>)
21   }
22   return _wrapper
23 }
24 // 第一次简化
25 let Wrapper = function(Component) {
26   return function _wrapper(props){
27     return (
28       <div>
29         {props.schoolName}
30         <hr />
31         <Component />
32       </div>)
33   }
34 }
35 //第二次简化
36 let Wrapper = function(Component) {
37   return (props) => {
38     return (
39       <div>
40         {props.schoolName}
41         <hr />
42         <Component />
43       </div>)
44   }
45 }
46 // 第三次简化
47 let Wrapper = (Component) =>(props) => 
48       (
49       <div>
50         {props.schoolName}
51         <hr />
52         <Component />
53       </div>
54       )
55 
56 //整理
57 let Wrapper = (Component) =>(props) => <div> {props.schoolName} <hr /> <Component /> </div>
58         
71 let Root = (props) => <div>Root</div>
72 
73 // 返回新组件
74 let NewComp = Wrapper(Root)
75 ReactDom.render(<NewComp schoolName="jerry"/>, document.getElementById('newroot'))

   测试:加入子组件(无状态组件)

  

 

 12、装饰器  

   新版的ES2016中增加了装饰器的支持,因此可以使用装饰器来改造上面的代码。

  装饰器是装饰函数,类,不能对一个变量装饰(这样是不对的)

   

   ES 2016 的装饰器只能装饰类,所以,将Root改写成类

     

   让Root 也显示schoolName

    

 

13、带参装饰器

   想给装饰器函数增加一个id 参数

 1 import React from 'react';
 2 import ReactDom from 'react-dom';
 3 
 4 let Wrapper = (id, Component) =>(props) => 
 5       (
 6       <div id={id}>
 7         {props.schoolName}
 8         <hr />
 9         <Component />
10       </div>
11       )
12 
13 // 柯里化
14 let Wrapper = id =>  Component => (props) => 
15       (
16       <div id={id}>
17         {props.schoolName}
18         <hr />
19         <Component {...props}/>
20       </div>
21       )
22 
23 
24 @Wrapper('123') // Root = wrapper("123")(Root) = (props) => .....
25 
26 class Root extends React.Component {
27   render(){
28     return <div>Root ----  {this.props.address}</div>
29   }
30 }
31 
32 ReactDom.render(<Root schoolName="jerry" address="somewhere"/>, document.getElementById('newroot'))

 

     

  

 

  

 

 

 

 

 

 

    

 

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯