JSX

181 阅读6分钟

什么是jsx

JSX是一种JavaScript的语法扩展(eXtension),也在很多地方称之为JavaScript XML,因为看起来就是一段XML语法; JSX其实是嵌入到JavaScript中的一种结构语法,在javaScript中以一定的结构实现。

React认为渲染逻辑本质上与UI逻辑存在内在耦合

比如UI需要绑定事件(button、a原生等等);比如UI中需要展示数据状态,在某些状态发生改变时,又需要改变UI; 所以事件和结构是可以放在一起的。 他们之间是密不可分,所以React没有讲标记分离到不同的文件中,而是将它们组合到了一起,这个地方就是组件 (Component);

JSX的书写规范

JSX的顶层只能有一个根元素,我们很多时候会在最外层包裹一个div(后续React推出了不占据Dom结构的Fragment) 为了方便阅读,我们通常在jsx的外层包裹一个小括号(),这样可以方便阅读,并且jsx可以进行换行书写; JSX中的标签可以使单标签,也可以是双标签,如果是单标签,必须以/>结尾

JSX中的注释

单行注释和多行注释,都需要在大括号{}中编写 { //我是单行注释 } {/我是一段注释/}

JSX中嵌入变量

当变量是Number、String、Array类型时,可以直接显示; 当变量是null、undefined、Boolean类型时,内容显示为空(如果想让其展示可以将其转换为字符串进行展示); 对象类型不能作为变量嵌入('not valid as a React child')

{ // 1.在{}中可以正常显示显示的内容 name: "lanzhou", // String age: 20, // Number names: ["abc", "cba", "nba"], // Array

      // 2.在{}中不能显示(忽略)
      test1: null, // null
      test2: undefined, // undefined
      test3: true, // Boolean

      // 3.对象不能作为jsx的子类
      friend: {
        name: "lanzhou",
        age: 20
      }

}

JSX嵌入表达式

运算表达式 三元运算符 执行一个函数

render() { const {firstName, lastName, isLogin} = this.state; return (

{/1.运算符表达式/}

{ firstName + " " + lastName }

{20* 50}

{/2.三元表达式/}

{ isLogin ? "欢迎回来~": "请先登录~" }

{/3.进行函数调用/}

{this.sayHello()}

) }

JSX绑定属性

JSX绑定普通属性 JSX绑定class JSX绑定style render() { const { title, imgUrl, link, active } = this.state; return (

{/* 1.绑定普通属性 */}

我是标题

<img src={getSizeImage(imgUrl, 140)} alt=""/> 百度一下

        {/* 2.绑定class */}
        <div className="box title">我是div元素</div>
        <div className={"box title " + (active ? "active": "")}>我也是div元素</div>

        {/* 3.绑定style */}
        <div style={{color: "red", fontSize: "50px"}}>我是div,绑定style属性</div>
      </div>
  )

JSX绑定事件

JSX中绑定事件类似在HTML原生中绑定事件,只不过React中事件命名采用小驼峰(camelCase),而不是纯小写; 但是我们会发现在我们绑定的回调事件中访问我们对应的this会是undefined,这是因为对应的回调函数是React内部帮我们去进行调用的,React无法确定对应的this所以采用的是callback.apply(undefined,[])方式调用,改变了this的指向为undefined。但是我们往往需要访问到的this是我们React组件对象。解决方法有以下三种:

increment = () => { console.log(this); } render() { return (

{/* 1.方案一: bind绑定this(显示绑定) */} 按钮1 按钮2 按钮3

        {/* 2.方案二: 定义函数时, 使用箭头函数 */}
        <button onClick={this.increment}>+1</button>

        {/* 2.方案三(推荐): 直接传入一个箭头函数, 在箭头函数中调用需要执行的函数*/}
        <button onClick={() => { this.decrement(666) }}>-1</button>
      </div>
    )
 }

绑定事件参数的传递,推荐采用绑定this的方案三,既方便的传递我们想要传递的参数,还可以非常简单的获取到事件对象event

render() { return (

    { this.state.movies.map((item, index, arr) => { return ( <li className="item" onClick={ e => { this.liClick(item, index, e) }} title="li"> {item} ) }) }
) }

JSX条件渲染

某些情况下,页面会根据不同的条件展示不同的内容,或者决定是否渲染某部分内容。 在Vue中给我们提供了对应的v-if、v-show指令,然而React中实现条件渲染的方式有那些呢?

条件判断语句 三元运算符 与运算符 && v-show效果(主要是控制html标签的display属性是否为none)

render() { const { isLogin } = this.state;

    // 1.方案一:通过if判断: 逻辑代码非常多的情况
    let welcome = null;
    let btnText = null;
    if (isLogin) {
      welcome = <h2>欢迎回来~</h2>
      btnText = "退出";
    } else {
      welcome = <h2>请先登录~</h2>
      btnText = "登录";
    }

    return (
      <div>
        {welcome}
        
        {/* 2.方案二: 三元运算符 */}
        <button onClick={e => this.loginClick()}>{isLogin ? "退出" : "登录"}</button>
        <h2>{isLogin ? "你好啊, 666": null}</h2>

        {/* 3.方案三: 逻辑与&& */}
        {/* 逻辑与: 一个条件不成立, 后面的条件都不会进行判断了 */}
        <h2>{ isLogin && "你好啊, 666" }</h2>
        { isLogin && <h2>你好啊, 666</h2> }
      </div>
    )
 }

{/* 4.方案四: 根据一个状态动态更改对应标签的display属性的值为block或none */} render() { const { isLogin} = this.state; const titleDisplayValue = isLogin ? "block": "none"; return (

<button onClick={e => this.loginClick()}>{isLogin ? "退出": "登录"} <h2 style={{display: titleDisplayValue}}>你好啊, 666
) } loginClick() { this.setState({ isLogin: !this.state.isLogin }) }

JSX列表渲染

在React中列表生成及展示运用最多的是js中高阶函数,当然我们也可以运用for循环来进行列表的生成及展示。 render() { return (

名字列表

    { this.state.names.map(item => { return
  • {item}
  • }) }

        <h2>数字列表(过滤1)</h2>
        <ul>
          {
            this.state.numbers.filter(item => {
              return item >= 50;
            }).map(item => {
              return <li>{item}</li>
            })
          }
        </ul>

        <h2>数字列表(过滤2)</h2>
        <ul>
          {
            this.state.numbers.filter(item => item >= 50).map(item => <li>{item}</li>)
          }
        </ul>

        <h2>数字列表(截取)</h2>
        <ul>
          {
            this.state.numbers.slice(0, 4).map(item => {
              return <li>{item}</li>
            })
          }
        </ul>
      </div>
    )
  }

JSX本质浅析

JSX实际上仅仅是React.createElement(type, config, children)方法的语法糖,该方法接收三个参数: type,当前ReactElement的类型,如果是标签元素,那么使用字符串表示“div”,如果是组件元素直接使用组件的名称就可以。 config,我们在JSX中绑定的属性会在config对象中以键值对的形式存在。 children,存放标签中的内容,以children数组的形式存储 我们知道JSX是通过babel进行解析的,我们编写JSX需要依赖babel。

如果我们直接使用React.createElement()来编写代码,就不需要以来bable进行解析也可以正常的渲染显示。

我们通过React.createElement()方法最后返回得到的是一个ReactElement对象,这个ReactElement对象作用是什么?其实React利用ReactElement对象组成了一个JavaScript对象树,这个对象树就是我们经常讲的一个概念--虚拟DOM

流程大概如下: 首先是我们编写的JSX代码经过bable编译解析成对应的React.createElement()方法形式,经过React.createElement()方法调用返回我们对应的ReactElement对象树(虚拟DOM树),对应的ReactElement对象树经过ReactDOM.render()方法转换为真正的DOM在我们的浏览器进行渲染。

为什么采用虚拟DOM呢?

很难跟踪状态发生的改变:原有的开发模式,我们很难跟踪到状态发生的改变,不方便针对我们应用程序进行调试; 操作真实DOM性能较低:传统的开发模式会进行频繁的DOM操作,而这一的做法性能非常的低; DOM操作非常耗费性能: document.createElement本身创建出来的就是一个非常复杂的对象 link.juejin.cn/?target=htt… DOM操作会引起浏览器的回流和重绘,所以在开发中应该避免频繁的DOM操作