React总结1

3 React技术

React是Facebook于2013年开源的框架。React解决的是前端MVC框架中的View视图层的问题。

3.1 Virtual DOM*

DOM(文档对象模型Document Object Model)
将网页内所有内容映射到一棵树型结构的层级对象模型上,浏览器提供对DOM的支持,用户可以是用脚本调用DOM API来动态的修改DOM结点,从而达到修改网页的目的,
这种修改是浏览器中完成,浏览器会根据DOM的改变重绘改变的DOM结点部分。
修改DOM重新渲染代价太高,前端框架为了提高效率,尽量减少DOM的重绘,提出了Virtual DOM,所有的修改都是现在VirtualDOM上完成的,通过比较算法,
找出浏览器DOM之间的差异,使用这个差异操作D0M,浏览器只需要渲染这部分变化就行了。

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

Virtual DOM实际上就是内存中的一个数据结构、对象,本身不属于浏览器,而是在浏览器中通过js引擎构建出来的一个对象。不管怎么样,都是在浏览器中跑得东西,和服务器端没什么关系。

前后端,一般前后端指的是web的前后端,前端往往指的是浏览器,后端指的是wsgi、server这些东西

前端技术,通常指浏览器中能够跑的东西:CSS,HTML,JS

3.2 支持JSX语法

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

React.render(
    <div>
        <div>
            <div>content</div>
        </div>
    </div>,
    document.getElementById('example')
)

3.3 测试程序

替换src/index.js程序

// 基于React框架,使用JSX语法,替换上述代码
// 1、导入react模块
import React from "react";  // 导入react模块
import ReactDOM from "react-dom";  // 导入react的DOM模块

// 2、创建React元素
class Root extends React.Component{ // 组件类定义,从React.Component类上继承,这个类生成JSXElement对象,即React元素
  state = {
    p1: "www.baidu.",
    p2: "com"
  } // 每一个react组件component都有一个状态变量state,它是一个js对象,可以定义属性来保存值。如果状态发生变化,会触发UI重新渲染。state是组件内部的私有属性
  render(){ // 渲染函数,返回组件中渲染的内容, 注意,只能返回唯一一个顶级元素回去
    console.log("render log");
    setTimeout(() => this.setState({p2: "net"}), 3000); // 延时函数:设置异步修改状态  // state的变化,会触发调用render,所以,render内最好不要对state进行任何改变,虽然可以,但是尽量不要。
    // this.state.p2 = "net"
    return <div>{this.state.p1 + this.state.p2}</div>;  // div是一个容器,可以包含其他html标记。这里只能包含一个顶级元素
  }
}

// 3、将React元素添加到DOM的Element元素中并渲染
ReactDOM.render(<Root/>, document.getElementById('root'));  // 渲染,将组件类挂载到DOM树中要被渲染的元素中去。第一个参数是JSXElement对象;第二个参数是DOM的Element元素。指定DOM树中被渲染的元素id,将React元素对DOM树中的元素进行替换并重新渲染。

// 4、保存后文件自动编译
  • html中的元素分类:
    学习html后, 你会了解一些基本的html元素(Element), 如p, h1~h6, br, div, li, ul, img等.如果将这些元素细分, 又可以分别归为顶级 (top-level)元素,块级 (block-level)元素和内联 (inline)元素.

1、Top-level element 【顶级元素】: { html, body, frameset }。包括html, body, frameset, 表现如Block-level element, 属于高级块级元素.
2、Block-level element 【块级元素】: { p, h1~h6, div, ul }。顾名思义就是以块显示的元素,高度宽度都是可以设置的。比如我们常用的 p, h1~h6, div, ul 默认状态下都是属于块级元素。块级元素比较霸道,默认状态下每次都占据一整个行,后面的内容也必须再新起一行显示。当然非块级元素也可以通过css的 display:block;将其更改成块级元素。此外还有个特殊的,float也具有此功能。块级元素能够独立存在, 一般的块级元素之间以换行(如一个段落结束后另起一行)分隔。块级元素是构成一个html的主要和关键元素, 而任意一个块级元素均可以用Box model来解释说明.
3、Inline element 【内联元素】: { a, br, em, img, li, span }通俗点来说就是文本的显示方式,与块级元素相反,内联元素的高度宽度是不可以设置的,其宽度就是自身文字或者图片的宽度。我们常用到的<a>、<span>、<em>都属于内联元素。内联元素的显示特点就是像文本一样的显示,不会独自占据一个行。 当然内联元素也能变成块级元素,那就是通过css的display:inline;和float来实现。内联元素依附其他块级元素存在, 紧接于被联元素之间显示, 而不换行.

注意:
1、React组件的render函数return,只能是一个顶级元素。组件是最小封装对象
2、JSX语法是XML,要求所有元素闭合,注意<br />不能写成<br>

3.4 JSX规范*

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


3.5 组件状态state*

每一个react组件component都有一个状态变量state,它是一个js对象,可以定义属性来保存值。
如果状态发生变化,会触发UI重新渲染。
state是组件内部的私有属性。

class Root extends React.Component{ // 组件类定义,从React.Component类上继承,这个类生成JSXElement对象,即React元素
  state = {
    p1: "www.baidu.",
    p2: "com"
  } // 每一个react组件component都有一个状态变量state,它是一个js对象,可以定义属性来保存值。如果状态发生变化,会触发UI重新渲染。state是组件内部的私有属性
  render(){ // 渲染函数,返回组件中渲染的内容
    console.log("render log");
    // this.setState({p2: "net"}); // 不可以对还在更新中的state使用setState
    setTimeout(() => this.setState({p2: "net"}), 3000); // 延时函数:设置异步修改状态,和上一行是两码事。
    // this.state.p2 = "net"
    return <div>{this.state.p1 + this.state.p2}</div>;  // div是一个容器,可以包含其他html标记。这里只能包含一个顶级元素
  }
}
  • state的变化,会触发调用render,所以,render内最好不要对state进行任何改变,虽然可以,但是尽量不要。
  • 延时函数:设置异步修改状态

3.6 复杂状态

将本目录中’./test.html’使用jsx进行替换。
可以将’./test.html’文件移动到上一层目录下,然后在浏览器中http://localhost:3000/test.html 进行访问查看效果。

class SubElement extends React.Component{
  render(){
    return <div>这是子元素SubElement</div>
  }
}


class Trigger extends React.Component{
  state = {
    flag: true
  }
  handlerClick(event){
    console.log("触发的事件ID为:" + event.target.id)
    alert("点击这里触发事件,事件ID为" + event.target.id)
    this.setState({flag: !this.state.flag})
  }
  render(){
    let x = this.state.flag?'true':'false';
    return (<div id="trig" onClick={this.handlerClick.bind(this)}>
      定义一个html标记div,div是分组,给这个标记起名字ID为trig,并注册一个事件onClick,事件捆绑一个函数handlerClick函数.当鼠标点击时,触发事件。
    事件一被触发立即调用与该事件绑定的函数,同时送一个参数进去, 这个参数不用管,这个参数是浏览器对象(event对象),由浏览器自动传入
      <SubElement/>
      {x}
    </div>)
  }
}

ReactDOM.render(<Trigger/>, document.getElementById("root2"))

3.7 props属性*

props,使得可以从外部给React组件传递数据。传入的这个数据如果是对象,还可以访问、修改对象的属性。
props的属性是只读的,不允许修改。

import React from "react";
import ReactDOM from "react-dom";

class SubElement extends React.Component{
  render(){
    console.log(this.props.name)
    console.log(this.props.parent, 'SubElement.props.parent.state.flag=' + this.props.parent.state.flag) // 还可以通过props传递的对象,修改、访问外层对象的元素
    
    return <div>这是子元素SubElement {this.props.children} {/*演示通过子元素,给props的children元素增加的属性*/}</div>
  }
}


class Trigger extends React.Component{
  state = {
    flag: true
  }
  handlerClick(event){
    alert("点击这里触发事件,事件ID为" + event.target.id)
    this.setState({flag: !this.state.flag})
    // this.props.name = "Trigger" // props元素只读,不允许修改
  }
  render(){
    let x = this.state.flag?'true':'false';
    return (<div id="trig" onClick={this.handlerClick.bind(this)}>
      <SubElement name="我是subElement" parent={this}>
        <hr />
        <div>我是subElement的children的元素</div> {/*演示通过子元素传入数据到props的children元素中*/}
      </SubElement>  {/*利用props属性,从组件外部给组件内部传递数据。这里的数据会保存到props属性中*/}
      点击这里触发一个事件,会弹出警告对话框。
    </div>)
  }
}

ReactDOM.render(<Trigger/>, document.getElementById("root2"))

总结

  • state是私有private属性,组件外无法直接访问,可以修改state,建议使用setState。
  • props是公有public属性,组件外也可以访问,只读。
  • 代码示例中,name="我是subElement",这个属性作为单一对象传递给组件,加入到组件的props属性中;parent={this},这里的this是Trigger组件本身。
  • 在Trigger中,使用JSX语法增加子元素,这些子元素,也会被加入到subElement的props.children中

3.8 构造器constructor

ES6使用构造器,为组件添加属性

import React from "react";
import ReactDOM from "react-dom";


class Trigger extends React.Component{
  // state = {flag: true}
  constructor(props){ /*ES6使用构造器,为组件添加属性。通过构造器添加属性,使代码可读性更好*/ 
    super(props); // 调用父类的constructor,需传入props属性。
    this.state = {flag: true}
  }

  handlerClick(event){
    alert("触发事件的ID为" + event.target.id)
    this.setState({flag: !this.state.flag})
  }
  render(){
    return (<div>点击这里触发一个事件,会弹出警告对话框。</div>)
  }
}

3.9 组件的生命周期管理*

组件的声明周期可分为三个状态:

  • Mounting: 挂载,表示组件已插入到真实的DOM树中
  • Updating: 正在本重新渲染
  • Unmounting: 已从真实的DOM树中移除

组件的生命周期状态,说明在不同时机访问组件,组件正处在生命周期的不同状态上。在不同的声明周期状态访问,就产生不同的方法。

生命周期的方法如下:

  • 装载组件触发

    • componentWillMount 在渲染前调用,在客户端也在服务端。只会在装载之前调用一次。

    • componentDidMount:在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout,setInterval或者发送AJAX请求等操作(防止异部操作阻塞U1)。只在装载完成后调用一次,在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构造器是最早被执行的函数
  • 要触发更新声明周期函数,需要更新stateprops

3.10 无状态组件*

从React15.0开始,支持无状态组件。定义为:

import React from "react";  // 导入react模块
import ReactDOM from "react-dom";  // 导入react的DOM模块

function Root(props){
  return <div>{props.name}</div>;
}

ReactDOM.render(<Root name={"test"}/>, document.getElementById("root"));

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

  • 无状态组件函数应该提供一个参数props,返回一个React元素。
  • 无状态组件函数本身就是render函数。

改写定义代码为:

import React from "react";  // 导入react模块
import ReactDOM from "react-dom";  // 导入react的DOM模块

let ROOT = props => <div>{props.name}</div>;
ReactDOM.render(<Root name={"test"}/>, document.getElementById("root"));

总结

react中,虚拟dom有可能会被文档。组件的state、props、生命周期一般都会被问,需要理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个两个四个三

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值