1、简介  

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

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

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

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

2、Virual DOM

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

   (React 框架)React技术 Python 第1张

    (React 框架)React技术 Python 第2张

  将网页内所有内容映射到一颗树形结构的层级对象模型上,浏览器提供对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 被设计用来显示数据,其焦点是数据的外观

  (React 框架)React技术 Python 第3张

4、测试程序 

  修改 /src/index.js: 

    (React 框架)React技术 Python 第4张

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

      (React 框架)React技术 Python 第5张

  启动 npm start 后

    (React 框架)React技术 Python 第6张   (React 框架)React技术 Python 第7张

    (React 框架)React技术 Python 第8张

  程序解释

    (React 框架)React技术 Python 第9张

    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) 

     (React 框架)React技术 Python 第10张

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

     (React 框架)React技术 Python 第11张  (React 框架)React技术 Python 第12张

    注意:

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

     JSX 规范:

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

         (React 框架)React技术 Python 第13张

5、组件状态 state 

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

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

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

  依然修改/src/index.js

    (React 框架)React技术 Python 第14张

    解决方式1:

      (React 框架)React技术 Python 第15张  (React 框架)React技术 Python 第16张

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

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

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

  复杂状态的例子  

    (React 框架)React技术 Python 第17张

    浏览器结果:

    (React 框架)React技术 Python 第18张   ========》点击后

 

    (React 框架)React技术 Python 第19张

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

 

  HTML DOM的JavaScript 事件

      (React 框架)React技术 Python 第20张

      (React 框架)React技术 Python 第21张

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

      (React 框架)React技术 Python 第22张

      (React 框架)React技术 Python 第23张

 

    分析:

      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中

      (React 框架)React技术 Python 第24张

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

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

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

      (React 框架)React技术 Python 第25张

7、构造器constructor:

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

  (React 框架)React技术 Python 第26张  (React 框架)React技术 Python 第27张

  (React 框架)React技术 Python 第28张

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中移除的时候,立即被调用

          (React 框架)React技术 Python 第29张

    有图可知:

      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"));

 

   结果:

(React 框架)React技术 Python 第30张         (React 框架)React技术 Python 第31张

 

     增加,更新组件函数:

     演示 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之后,

   (React 框架)React技术 Python 第32张

 

 

 

 

 

 

 

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

 

 

 

 10、无状态组件

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

  (React 框架)React技术 Python 第33张  

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

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

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

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

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

    (React 框架)React技术 Python 第34张

 

 11、高阶组件

   (React 框架)React技术 Python 第35张

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

  (React 框架)React技术 Python 第36张

  简化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'))

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

  (React 框架)React技术 Python 第37张

 

 12、装饰器  

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

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

   (React 框架)React技术 Python 第38张

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

     (React 框架)React技术 Python 第39张

   让Root 也显示schoolName

    (React 框架)React技术 Python 第40张

 

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'))

 

     

  (React 框架)React技术 Python 第41张

 

  (React 框架)React技术 Python 第42张

 

 

 

 

 

 

    

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄