JSX语法

1,677 阅读7分钟

JSX介绍

JavaScript XML, React 使用 JSX 来替代常规的 JavaScript。JSX 是一个看起来很像 XML 的 JavaScript 语法扩展,在js文件中可以用变量来保存标签和js文件中写标签。JSX就是一种插值语法,它经过打包工具编译后本质上还是js语法,因为变量既可以保存数据也可以保存标签,所以React中没有插槽

JSX特点

  1. JSX可以直接在js中混用,React项目利用babel做了对js的编译,所以可以直接在js里写jsx。
  2. JSX几乎和js一样,不同点在于JSX可以更方便的写html在js里,写在js里的html最后会被编译成一个js对象,也可以用react自带的createElement创建这个对象。

JSX有以下优点:

  • JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
  • 它是类型安全的,在编译过程中就能发现错误。
  • 使用 JSX 编写模板更加简单快速。
  • 作用: 用来创建react虚拟DOM(元素)对象
  • 标签名任意: HTML标签或其它标签
  • 标签属性任意: HTML标签属性或其它
let App=<div>hello react</div>;

它不是字符串也不是HTML/XML标签,最终产生的就是一个JS对象。

React和JSX是互相独立的,React不一定要使用JSX,可以用react自带的createElement创建组件模版这个对象。JSX编译成的js对象在React中就是编译成了react的Element对象;在vue中编译成了vue的组件对象。

function FnHello() {
    return React.createElement("div",[],"hello")
}

React.createElement方法参数:

  • 第一个参数:用于确定创建什么元素
  • 第二个参数:创建的元素有没有什么属性,空数组代表没有属性
  • 第三个参数:组件的内容

JSX语法本质

image.png

JSX只是创建react-element对象的一种快捷方式,最终渲染显示在页面的还是react-element对象。

JSX基本语法规则

  • 当遇到<>就会解析为标签:如果是html语法标准的标签就会直接解析为同名元素,比如nav或者Nav等html语法标准的标签不能做为组件的标签使用。如果是其他标签需要特别解析就会创建一个对象即组件。而vue是在编译时vue文件中导出一个对象,导出的对象当做标签用。在使用标签时同样如果是驼峰命名在当做标签使用时可以用连字符号。

  • <App title="200"/>当做标签用,代码的意义可以理解为相当于 new App(200)但实际并不是,webpack打包编译时会创建一个对象。

  • 遇到{}的就会以JS的语法解析,{}中的就是js变量或者js表达式,标签中的js代码必须用{ }包含

第一种:引入组件

import React from 'react';//用于创建组件的
import ReactDOM from 'react-dom/client';//用于渲染页面的
import App from "./App" //引入App组件

const root = ReactDOM.createRoot(document.getElementById('root'));//给根元素内部渲染组件模板
root.render(
    <App />
);//给根元素内部渲染组件模板

第二种:变量保存标签

let App=<div>hello react</div>;
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
     App
);//给根元素内部渲染组件模板

第三种:函数返回一个标签

function App(){
  let a=0;
  if(flase){
    return <div>hello react{a}</div>;
  }else{
    return <div>hello react{a+1}</div>;
  }
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
     <App />
);//给根元素内部渲染组件模板

使用JSX

所以组件可以写在.jsx文件中,组件的写法分为两种方式一个是类组件,一个是函数组件。类组件可以继承React导出的Component,创建有状态的组件(即可以响应式数据),函数组件是无状态的组件,就像是一个模板组件,函数组件如果需要有状态需要引入hook才能办到。

JSX的注释分为//或者/* */在{}中只能是/* */。在标签内部的注释需要花括号,在标签外的的注释不能使用花括号

ReactDOM.render(
    /*标签外部的注释 */
    <h1>我是标题 {/*标签内部的注释*/}</h1>,
    document.getElementById('example')
);
import React from "react";

class App extends React.Component{
    constructor(){
        super()
    };
    // 或者 /* */ 是jsx注释 {只能是/* */}
    render(){
        return(
            <div>777{/*注释*/}</div>
        )
    }
}
export default App;

return 后面返回的标签必须加括号是因为js语法换行相当于是分号,该函数会返回undefined而不是换行后的标签,不加括号后面的返回的标签则不能换行。

JSX中渲染不同内容区别

  • 字符串、数字:直接渲染
  • 对象:只能渲染element对象,会把对象当成一个组件渲染在页面上
  • 数组:把数组里的每一项单独渲染
  • 表达式:运行表达式,渲染表达式运行的结果
  • 方法:无法渲染
  • 布尔值:不渲染任何内容
  • undefined、null:不渲染任何内容

JSX错误语法

错误写法:
import React from "react";

class App extends React.Component{
    constructor(){
        super()
    };
    render(){
        return(
            <div>777{/*注释*/}</div>
            <h1>666</h1>
        )
    }
}
export default App;

代码中能够嵌套多个 HTML 标签,但需要使用一个标签元素包裹所有的标签,JSX表达式必须具有一个父元素

JSX表达式必须具有一个父元素,而该父元素只是用来包裹标签,实际上不会有其他作用,在使用一个div标签就比较浪费,所以在Vue中会使用template标签,在微信小程序开发中使用的是block元素,而在React中就是一个空标签<>...</>,他们都的作用就是原生DOM中的fragment元素,它们都不会被渲染在页面上,就不会造成一个标签元素的浪费。

import React from "react";
import Des from "./des.js";
class App extends React.Component{
    constructor(){
        super()
    };
    // 或者 /* */ 是jsx注释 {只能是/* */}
    render(){
        return(
            <div>
                <h1>777{/*注释*/}</h1>
                <des />
            </div>
            
        )
    }
}
export default App;

image.png

如果需要呈现一个React组件,必须以大写字母开始标签,所以react的命名规范,不是一个建议而是必须照做。需要注意的是React项目在webpack打包时要求import引入的代码放在上面

独立文件

可以将React JSX代码可以放在一个独立文件上,可以是.jsx文件也可以是.js文件,只需要在不同的js文件中引入即可。

类组件(VScode的快捷指令rcc)

import React, { Component } from 'react' 
//{ Component } 具名导出,React默认导出
import sinadata from './sina.js'
export default class Des extends Component {
  render() {
        let objarr=sinadata.statuses;
        console.log(objarr);
    return (
      <div>
        {
            objarr.map(el=>{
                return(
                    <div key={el.id}>
                        <img src={el.user.profile_image_url} />
                        <div>{el.user.screen_name}</div>
                        <div>{el.text}</div>
                    </div>
                )
            })
        }
      </div>
    )
  }
}

函数组件可以是普通函数也可以是箭头函数(VScode的快捷指令rfc)

import React from 'react'

export default function home() {
  return (
    <div>home</div>
  )
}

let First=()=>{
    return (
      <div>First</div>
    )
  }
  
export default First;

React的样式

React 可以使用内联样式也可以外部引入css文件。

//外部引入css文件
import React from "react";
import Home from "./home.js";
import First from "./First.js";
import './gold.css';
class App extends React.Component{
    constructor(){
        super()
    };
    render(){
        let gold='text';
        return(
            <div>
                <h1 className={gold}>777{/*注释*/}</h1>
                <Home />
                <First />
            </div>
            
        )
    }
}
export default App;

image.png

使用内联样式
export default function Home() {
    let purple={
        color:"purple",
        fontSize:37 //等价于fontSize: '37px',
    }
  return (
    <div style={purple}>home</div>
  )
}

使用内联样式时React会在指定元素数字后自动添加 px ,内联样式变量需要写一个对象。

image.png

插值表达式

可以在 JSX 中使用 JavaScript 表达式以及变量。表达式写在花括号 {} 中,就是插值表达式。

import React from "react";
class App extends React.Component{
    constructor(){
        super()
    };
    render(){
        var a=20
        function fn(){return "hello"}
        return(
           <div>
              <h1>{a+1}</h1>
              <h3>{fn()}</h3>//函数的返回结果
           </div>
            
        )
    }
}
export default App;

条件渲染

  • 三目运算符 在 JSX 内部不能使用 if else 语句,但可以使用 三目运算 表达式来替代。
import React from "react";
import './gold.css';
class App extends React.Component {
    constructor() {
        super()
    };
    render() {
        let gold = 'text';
        let flag = false;
        return (
            <div>
                <div>{flag ? true : <h1 className={gold}>false</h1>}</div>
            </div>

        )
    }
}
export default App;

image.png

  • 可以在JSX外部使用if语句
import React from "react";
import './gold.css';
class App extends React.Component {
    constructor() {
        super()
    };
    render() {
        let gold = 'text';
        let flag = true;
        let box=false;
        let msg='goldn star'
        if(flag){
            box=<h1 className={gold}>{msg}</h1>
        }
        return (
            <div>
                <div>{box}</div>
            </div>

        )
    }
}
export default App;

image.png

插值语法中用数组

JSX 允许在模板中插入数组,数组会自动展开所有成员,所以没有v-for的语法。绑定key的意义同样是为了高效渲染DOM。

import React from "react";
import './gold.css';
class App extends React.Component {
    constructor() {
        super()
    };
    render() {
        let arr=['vue','react','angular','fluter','uniapp','react native']
        return (
            <div>
                {arr}
            </div>

        )
    }
}
export default App;

image.png

没有绑定key会报警告,但不会影响页面显示

image.png

import React from "react";
import './gold.css';
class App extends React.Component {
    constructor() {
        super()
    };
    render() {
        let arr=['vue','react','angular','fluter','uniapp','react native']
        return (
            <div>
                {
                arr.map((el,index)=>{
                    return <h4 key={index}>{el}</h4>
                })
                }
            </div>

        )
    }
}
export default App;

image.png

数组的map方法会返回一个新数组,原数组有几个元素就会调用回调函数多少次,新数组的元素就是装有回调函数的返回值。然后该{}返回的就是一个数组,就数组中装有的元素就是[<h4>vue</h4>,<h4>react</h4>,...,<h4>react native</h4>],该数组就会自动展开所有成员,渲染的效果如上。

列表渲染

JSX通过数组的map函数就可以进行列表渲染

import React, { Component } from 'react' //{ Component } 具名导出,React默认导出
import sinadata from './sina.js'
export default class Des extends Component {
  render() {
        let objarr=sinadata.statuses;
        console.log(objarr);
    return (
      <div>
        {
            objarr.map(el=>{
                return(
                    <div key={el.id}>
                        <img src={el.user.profile_image_url} />
                        <div>{el.user.screen_name}</div>
                        <div>{el.text}</div>
                    </div>
                )
            })
        }
      </div>
    )
  }
}

image.png