Skip to content

使用 JSX 书写标签语言

JSX (JavaScript XML) 是由 Facebook 开发的。它是一种 JavaScript 语法扩展,可以让你在 JavaScript 文件中书写类似 HTML 的标签。

JSX 并不是原生的 JavaScript 语法,需要通过 Babel 等工具编译成标准的 JavaScript 代码。

为什么 React 将标签和渲染逻辑耦合在一起

网页是构建在 HTML、CSS 和 JavaScript 之上的。多年以来,web 开发者都是将网页内容存放在 HTML 中,样式放在 CSS 中,而逻辑则放在 JavaScript 中。

html
<body>
    <div id="login">
        <h1>登录模块</h1>
        <button onclick="login()">登录</button>
    </div>

    <div id="register">
        <h1>注册模块</h1>
        <button onclick="register()">注册</button>
    </div>
</body>

<script>
    const type = 'login' // 当前为登录模块

    if (type === 'login') {
        document.getElementById('login').style.display = 'block'
        document.getElementById('register').style.display = 'none'
    }

    if (type === 'register') {
        document.getElementById('register').style.display = 'block'
        document.getElementById('login').style.display = 'none'
    }

    function login() {
        console.log('login')
    }
    function register() {
        console.log('register')
    }
</script>

但随着 Web 的交互性越来越强,页面上的内容基本上都是由逻辑去控制。这也是为什么在 React 中,标签和逻辑耦合在一起的原因。

jsx
import Register from './Register'
import Login from './Login'

export default function Form() {
    const type = 'login' // 当前为登录模块

    return <>{type === 'login' ? <Login /> : <Register />}</>
}
jsx
export default function Login() {
    const submit = () => {
        console.log('login')
    }

    return (
        <>
            <h1>登录模块</h1>
            <button onClick={submit}>登录</button>
        </>
    )
}
jsx
export default function Register() {
    const submit = () => {
        console.log('register')
    }

    return (
        <>
            <h1>注册模块</h1>
            <button onClick={submit}>注册</button>
        </>
    )
}

这种模式更适合组件化,方便维护和复用。例如要改登录的逻辑代码,只需要到 Login.jsx 文件修改即可,无需关心其他代码,也不会因为改动而影响其他文件。

JSX !== React

JSX and React 是相互独立的东西。但它们经常一起使用,但你可以单独使用它们中的任意一个,JSX 是一种语法扩展,而 React 则是一个 JavaScript 的库。

jsx
import { useState } from 'react' // 在 React 库中使用 useState 钩子

export default function Form() {
    const [text] = useState('Hello world!')

    // 使用 JSX 语法
    return <h1>{text}</h1>
}

JSX !== HTML

JSX 并不是 HTML,JSX 语法更加严格并且相比 HTML 有更多的规则。所以你将 HTML 的代码直接复制到 JSX 中,可能无法正常工作。

这里将举例一个错误的案例,假设你现在有一段可在 Web 中运行的 HTML 标签。

html
<div id="login">
    <h1>登录模块
    <button >登录</button>
</div>

<div id="register">
    <h1>注册模块
    <button>注册</button>
</div>

现在将上面的 HTML 转化为 JSX 代码,直接拷贝到 React 组件中。

jsx
export default function Form() {
    return (
        <div id="login">
            <h1>登录模块
            <button>登录</button>
        </div>

        <div id="register">
            <h1>注册模块
            <button>注册</button>
        </div>
    )
}

其实这样是不能工作的!

首先是 JSX 只允许返回一个根元素,如果你不想在标签中增加一个额外的 <div>,可以用 <></> 元素来代替。

jsx
export default function Form() {
    return (
        <>
            <div id="login">
                <h1>登录模块
                <button>登录</button>
            </div>

            <div id="register">
                <h1>注册模块
                <button>注册</button>
            </div>
        </>
    )
}

其次是标签必须要闭合

jsx
export default function Form() {
    return (
        <>
            <div id="login">
                <h1>登录模块</h1>
                <button>登录</button>
            </div>

            <div id="register">
                <h1>注册模块</h1>
                <button>注册</button>
            </div>
        </>
    )
}

最后是标签的属性必须使用驼峰写法,而且一部分关键字不能使用,如 class 必须写成 className

jsx
export default function Form() {
    return <h1 className="title">登录模块</h1>
}

因为 JSX 最终会被编译转化为 JavaScript 语法,而 JSX 中的属性也会变成 JavaScript 对象中的键值对。我们也知道一个对象 Object 的键名不能使用一些特殊符号。