react-day01

前言:

  为了大家容易上手,我们循序渐进,由简到难,一步一步来。用ES5方式编写React语法,后期开发使用的是ES6+webpack+构建的方式编写项目。

  如果以下子将所有知识点罗列出来,大家肯定容易蒙圈,所以首先掌握基础语法。

  本节知识点base基础+JSX语法

 

主体:

(1)hello react

  

 

   此时刷新页面,发现报错。原因在于脚本里面写的是JSX代码,所以需要修改type为text/babel

  

babel:
    作用:将ES6转为ES5、将JSX语法解析为JS语法

  之所以说是JSX语法,分析如下

  1、JS函数语法

  

 

   2、传参不是字符串,而是HTML语法(XML简易版)

  

 

   因为页面无法直接解析,所以需要通过babel解析。但这里的 babel主要依赖第三方包配合解析

  

 

   如果将babel.min.js注释,则无法正常解析,页面为空,且不会报错

  

 

   

 

  所以JSX的语法解析主要依赖type=text/babel配合第三包完成

  

小结:
    1、本质:JS的一套视图层框架
    2、作用:高效渲染DOM和维护DOM层
   3、来源:Facebook打造,为了提升交互效率,全球最大的交互社区,页面响应用户操作过多,容易造成卡顿,所以React则致力与DOM层的渲染响应和维护

 

   

 

(2)JSX语法解析

  案例1:

  map语法:渲染无序列表

  

 

   

 

   JSX语法:

{}按照JS语法进行解析
<>按照XML语法进行解析

  案例2:

  

 

   

 

   注意:循环时,每个列表元素需要添加key,作为唯一元素索引... ...,简单理解为状态跟踪(Diff微分算法)

 

(3)基础组件与组件化

  组件化概念:

首先要了解一点:在React里,整体就是一个组件化设计,增强可复用性和维护性

  对比之前的简单数据、XML嵌套数组,这里我们再次加大数据复杂度

  

   这里会看到JSX的render里的return方法使用了(),详解React之JSX里render中return方法添加括号()或者[].

   此时render的第一个参数优点累赘繁多,所以接下来举个案例,将其提取出去

  

  我们可以看到,setInterval定时器里调用函数时没有加函数执行符(),详解浅谈JS之常问问题:setInterval和setTimeout调用函数为什么不加小括号()???.

   接下来看下组件化,首先创建组件,React里创建组件有两种方法,如下所示

注意:
    这里因为React的相关依赖包版本问题,我们换用其他版本(V16之前的版本)去进行测试,将之前的依赖包一一替换掉
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script>
    <script src="http://static.runoob.com/assets/react/browser.min.js"></script>

  

  1、第一种方法为React.createClass({})

  

   2、第二种方法为ES的class...extends...(ES6里Class 可以通过 extends 关键字实现继承)

  

   当然,构造器constructor主要用来来构造默认的属性和状态,这里可以省略

  

   3、如果想同时使用两组件,如下所示

  

   此时也可以看到组件的复用性,可以随意复用任意次数... ...

注意:
    1、组件名首字母大写,采用大驼峰命名
    2、render:function(){})可以简写为render(){})

  关于两种创建方式的区别,详解React创建组件两种写法:React.createClass和extends Component的区别.

 

(4)React组件嵌套

  组件之间可以互相嵌套

  

 

 

   

 

 

   且组件本身也具有业务逻辑,可以在内部循环

  

 

  注意:组件只能有一个根容器

 

   

 

 

   组件与组件间可以互相嵌套

  

 

 

   

 

(5)组件数据交互props

  父子组件间数据交互依赖props,组件交互里的数据传递

语法:this.props.attributeName属性名

  

  也可以传递多个参数

  

  接下来利用props做下案例完善,结合之前百度导航左右侧的案例

  1、左菜单导航

  

 

  2、右菜单导航

 

   

  3、根组件整合渲染

    

 

 

  4、接下来做下调整

  左侧和右侧的语法类似,所以这里去掉一个,并改名,然后利用props传递数据,来进行优化

  

  

 

 

   但是标签里无法直接传入数组,所以接着做下修改

  

 

 

   遗留1:父组件向子组件传值,不能是数组,需要由对象包含数组引用

 

  已解决1:   

  

 

 

 

(6)样式添加

  

 

 

   V15之前都是采用React.createClass({})方式创建组件,V16开始使用ES6的Class...extends...继承方式创建

  1、添加样式(class类名)

  

  

  

 

 

   2、style内联样式

  

 

   

 

   也可以依次写入:注意“这里的属性名必须改为小驼峰命名法则去写”

  

 

   注意:

1{{}}:style直接写入时是{{}}双花括号,直接将对象引用改为对象
2默认添加单位px:React 会自动添加 ”px” 后缀到内联样式为数字的属性后。如需使用 ”px” 以外的单位,请将此值设为数字与所需单位组成的字符串。
3属性名小驼峰:Style 中的 key 采用小驼峰命名是为了与 JS 访问 DOM 节点的属性保持一致(例如:node.style.backgroundImage )。
  浏览器引擎前缀都应以大写字母开头,除了 ms。因此,WebkitTransition 首字母为 ”W”。

  

 

   

 

   

 

(7)事件

  与之前 JS和jQuery事件绑定方式不同,React的事件绑定要采用该框架的绑定方式

  1、React.createClass方式创建的组件绑定事件

  

1、事件名绑定采用小驼峰
2、事件调用通过this.事件名
3、记住与render间加逗号,
4、方法位置:放到创建组件内部即可

  2、V16之后的ES6的Class类继承方式创建的组件

  

1、事件名绑定采用小驼峰
2、事件调用通过this.事件名
4、方法位置:放到创建组件内部即可
  不用加,逗号了

  其他事件类似

  

事件绑定:
    通过this找到当前组件里的方法

  1、V15版本之前创建组件方式,接下来打印this测试下

  

 

 

   

 

 

   控制台输出打印this指向当前React组件实例

   2、V16开始的ES6的Class继承创建组件方式,测试下this,如下所示

  

 

 

   

 

 

   控制台输出结果为undefined

  接着做下修改,如下所示,添加bind方法,改动this指向

  

 

  此时点击时控制台输出如下

  

 

 

   所以此时

this便指向当前组件,而不是传统操作里的window全局对象

  

 

 

   1、事件命名

  

 

 

   2、阻止默认事件

  

 

 

   

 

 

   3、添加事件监听

  

 

   

 

 

   

 

 

   

  或者利用箭头函数,如下所示

  

  

开发建议:
    建议直接在构造器中绑定

  

 

 

 

   

 

(8)React关键字: state状态

  之前已经介绍过一个关键字props,用于组件间的数据交互。

state关键字:组件内部的状态

例如:
    背景色为红色,点击后变蓝
    用户当前为普通用户,充值后变成VIP会员...

  之前的操作,都是基于DOM进行操作的,例如之前都是操作DOM原来的普通会员为灰色,VIP后变为红色。但React、Vue、小程序等框架里不再直接操作DOM,而是基于状态进行操作,基于组件内部状态state进行操作.所以现在部分公司在开发禁止使用jquery操作DOM。

  

 

 

   

 

 

   要求:点击按钮时,“开”与“关”的状态进行切换

  1、首先绑定事件

  

 

 

   2、初始化state值+读取渲染

  

 

  可以通过三目运算符进行状态切换,

 

   3、修改state状态值

  

 

 

   4、作用

  页面展示数据,需要后期用户操作更改或者用户登录状态、网络请求获取渲染数据... ...

  5、ES6新型Class继承方式

  

小结:
    setState会引起视图的重绘,相对于直接操作DOM来讲,React采用的虚拟DOM,即Virtual DOM技术,极大提升了重绘排版效率

  

 

 

   

 

 

   

 

 

   

   

 

(9)条件渲染

  

 

 

   

 

 

   

 

 

   

 

 

 

(10)state和props应用,区分两者

  1、组件一用于显示内容

 

 

  

 

 

   2、处理业务逻辑

  

 

 

   

 

 

   如上所示,一个组件用于数据定义和逻辑操作,另一个组件负责调用。后期易于拆分.

木偶组价&&智能组件:
  如上所示,第一个仅仅用于显示的组件称为“木偶组件(受控组件)”
  第二个称之为“智能组件(不受控组件)”,只负责业务逻辑,不进行渲染展示

 

 

(11)组件生命周期

  参考之前时钟的例子。在元素渲染章节中,我们只了解了一种更新 UI 界面的方法。通过调用 ReactDOM.render() 来修改我们想要渲染的元素:

  

 

 

    接下来,我们开始封装真正可复用的 Clock 组件。它将设置自己的计时器并每秒更新一次。

  1、添加props,实现组件通信,即父组件向子组件传值

  

  2、目前为止,忽略了一个关键的技术细节:Clock 组件需要设置一个计时器,并且需要每秒更新 UI

  

 

  所以接下来,向组件中添加局部的 state

 

   

 

 

   3、之后将计时器相关的代码添加到组件中,设置 Clock 的计时器并每秒更新它,此时,便需要用到生命周期去进行操作

  在具有许多组件的应用程序中,当组件被销毁时释放所占用的资源是非常重要的。

  

 

 

   

 

 

   componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行,所以,最好在这里设置计时器:

接下来把计时器的 ID 保存在 this 之中(this.timerID)。
尽管 this.props 和 this.state 是 React 本身设置的,且都拥有特殊的含义,但是其实你可以向 class 中随意添加不参与数据流(比如计时器 ID)的额外字段。
我们会在 componentWillUnmount() 生命周期方法中清除计时器:

  

 

 

   至此,现在时钟每秒都会刷新。

  

 

 

   小结:

                        

  

  

生命周期函数为红色,不需要主动调用,到一定阶段自动执行:
  getDefaultProps初始化默认props
  getInitialState初始化state
  componentWillMount组件挂载前
  render渲染
  componentDidMount组件挂载完毕
  componentWillUnmount组件卸载前
  ShouldComponentUpdate组件是否应该更新
  componentWillUpdatez组件更新前
  componentDidUpdate组件更新完毕
  componentWillReceiveProps组件更改props后执行

  运行中:对应3个分支,可以朝3个方向改变

  1、卸载:触发componentWillUnmount组件卸载前的生命周期

  2、状态state改变或者props改变,需要经由shouldComponentUpdate做判断,如下所示

react生命周期中的shouldComponentUpdate函数就派上用场了!shouldComponentUpdate函数是重渲染时render()函数调用前被调用的函数,
它接受两个参数:nextProps和nextState,分别表示下一个props和下一个state的值。并且,当函数返回false时候,阻止接下来的render()函数的调用,阻止组件重渲染
而返回true时,组件照常重渲染。
在render函数调用前判断:如果前后state中Number不变,通过return false阻止render调用

顺序验证如下:

完整代码:

 

      var UpdateTime = React.createClass({
        /*初始化props*/
        getDefaultProps(){
          console.log('初始化props---getDefaultProps')
        },
        /*初始化state*/
        getInitialState(){
          console.log('初始化state---getInitialState')
          return{
            now_date:new Date()
          }
        },
        /*挂载前*/
        componentWillMount(){
          console.log('挂载前---componentWillMount')
        },
        /*渲染*/
        render(){
          console.log('渲染---render')
          return (
            <h1>当前时间为{this.state.now_date.toLocaleTimeString()}</h1>
          )
        },
        /*挂载完毕*/
        componentDidMount(){
          console.log('挂载完毕---componentDidMount')
          this.timer = setInterval(() => {
            this.setState({
              // now_date: new Date()
            })
          }, 1000)
        },
        /*卸载前*/
        componentWillUnmount(){
          console.log('卸载前---componentWillUnmount')
          clearInterval(this.timer)
        },
        /*判断组件是否更新shouldComponentUpdate*/
        shouldComponentUpdate(nextProps,nextState){
          console.log('判断组件是否更新---shouldComponentUpdate')
          if(nextProps.now_date == this.state.now_date){
            return false
          }else{
            return true
          }
        },
        /*组件即将更新*/
        componentWillUpdate(){
          console.log('状态即将更新---componentWillUpdate')
        },
        /*组件更新完毕*/
        componentDidUpdate(){
          console.log('组件更新完毕---componentDidUpdate')
        }
      })
      ReactDOM.render(<UpdateTime />,document.getElementById('demo'))

6、生命周期函数作用:

  例如网络请求放到生命周期函数的某个位置,合理执行;

  页面重新渲染时,提示用户页面过大,刷新消耗流量,这个提示也可以放到合适生命周期例如componentWillUpdate里

 

 

(12)组件生命周期应用

  1、首先编写基础模板

  

 

   2、接下来要做个网络请求,将数据获取后读取展示到组件里,首先初始化state内部状态

  

 

   接下来可以利用json-server模拟服务器API建立启动服务器,如下所示

   

  3、结合生命周期读取网络接口数据,写到componentDidMount里,详见React在componentDidMount里面发送请求 .这里结合jQuery的ajax实现跨域请求

  

 

   

 

  打印出来的是一个数组,所以接下来我们将初始化 的数据改下,改为数组

  

   4、重定义覆盖数据

  

 

   但此时会发现控制台报错

  

 

   我们打印this做下测试

  

 

   发现this指向的是ajax对象,所以这里需要更改this指向,如下所示。这里使用bind改动this指向,关于相关知识点,详见 浅谈JS中的call、apply、bind方法.

  

 

   此时的this便指向当前组件实例。接下来覆盖之前的默认值,然后进行组件内部渲染遍历

  

 

   最终效果如下:

  

 

   这里会有一个问题:table表格设置边框属性border无效???详见React里table表格设置边框属性border="1"无效???.完整代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./dist/react.min.js"></script>
    <script src="./dist/react-dom.min.js"></script>
    <script src="./dist/browser.min.js"></script>
    <script src="./dist/jquery.js"></script>
    <style type="text/css">
        table.mytable {
            width: 40%;
            border: 2px solid #444;  
            border-spacing: 0;    
        }
        table.mytable tr,table.mytable th {border-bottom: 1px solid #444}
        table.mytable td,table.mytable th{
            border-right: 1px solid #444;
            border-bottom: 1px solid #444;
            padding: 5px;
        }
        table.mytable tr td:last-child{ border-right: 0 }
        table.mytable tr:last-child td{ border-bottom: 0 }
    </style>
</head>
<body>
    <div id="root"></div>
    <script type="text/babel">
        class Demo extends React.Component {
            constructor(props){
                super(props)
                this.state = {
                    usersInfo:[]
                }
            }
            componentDidMount(){
                $.ajax({
                    url: "http://localhost:3000/users",
                    type: "get",
                    success:function(result) {
                        this.setState({
                            usersInfo:result
                        })
                    }.bind(this)
                })
            }
            render(){
                return (
                    <div>
                        <h2>组件</h2>
                        <table  border="1">
                            <tr>
                                <th>id</th>
                                <th>姓名</th>
                                <th>年纪</th>
                                <th>性别</th>
                                <th>工作</th>
                            </tr>
                            {
                                this.state.usersInfo.map(function(item,index){
                                    return(
                                        <tr key={index}>
                                            <td>{item.id}</td>
                                            <td>{item.username}</td>
                                            <td>{item.age}</td>
                                            <td>{item.gender}</td>
                                            <td>{item.job}</td>
                                        </tr>
                                    )
                                })
                            }
                        </table>
                    </div>
                )
            }
        }
        ReactDOM.render(<Demo />,document.getElementById('root'))
    </script>
</body>
</html>

 

 

 

 

 

.

posted @ 2020-02-21 13:58  剑仙6  阅读(97)  评论(0)    收藏  举报
欢迎访问个人网站www.qingchun.在线