• (React 框架)React技术


    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 /> {/* 父组件的render,会引起下一级组件的更新流程,导致props重新发送,即使子组件props没有改变*/}
    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'))

         

      

      

        

    为什么要坚持,想一想当初!
  • 相关阅读:
    TcIC(Teamcenter集成CatiaV5)的安装
    centos7上使用bind解析子域名
    Windows10 家庭版(1903/1909)中用RDPWrapper-v1.6.2和autoupdate补丁开启远程桌面功能
    修改SQL Server Express 2019 sa用户密码的方法
    微星B450主板安装64G内存的一个小招数
    缩小xfs文件系统的CentOS/RedHat虚拟机硬盘的迂回方法
    MQL命令的打开方式
    台电TBook二合一本全新安装Windows10
    django_auth_ldap
    开始认真学计算机网络----computer network学习笔记(一)
  • 原文地址:https://www.cnblogs.com/JerryZao/p/9986008.html
Copyright © 2020-2023  润新知