React JSX语法介绍(JS XML)(一种JS语法扩展,允许在JS代码中编写类似HTML的标记语言)Babel编译

news2025/5/30 11:33:15

在线调试网站:https://zh-hans.react.dev/learn

文章目录

  • JSX:现代前端开发的声明式语法
    • 概述
    • JSX的本质与工作原理
      • 什么是JSX
      • JSX转换流程
    • JSX语法特性
      • 表达式嵌入(JSX允许在大括号内嵌入任何有效的JavaScript表达式)
      • 属性传递(JSX中的属性传递遵循特定的规则)
      • 条件渲染(JSX支持多种条件渲染模式)
      • 列表渲染(使用map方法渲染数组数据)
    • JSX与传统HTML的区别
      • 属性命名差异
      • 事件处理差异
    • JSX的优势
      • 声明式编程
      • 组件化开发
    • JSX编译过程
      • Babel转换示例
      • 编译配置
    • 最佳实践
      • 组件结构规范
      • 性能优化技巧
    • 常见问题与解决方案
      • Key属性的重要性
      • 事件处理中的this绑定
    • 总结

JSX:现代前端开发的声明式语法

概述

JSX(JavaScript XML)是Facebook开发的一种JavaScript语法扩展,它允许在JavaScript代码中编写类似HTML的标记语言。作为React生态系统的核心组成部分,JSX为开发者提供了一种更直观、更声明式的方式来描述用户界面。

JSX的本质与工作原理

什么是JSX

JSX本质上是一种语法糖,它将类HTML的语法转换为JavaScript函数调用。当编写JSX代码时,实际上是在创建React元素的描述,这些描述最终会被转换为虚拟DOM。

// JSX语法(我们写React时需要编写的代码,这种代码浏览器无法识别,需要通过Babel编译)
const element = <h1 className="greeting">Hello, World!</h1>;

// 转换后的JavaScript(经过Babel编译)
const element = React.createElement(
  'h1',                    // 元素类型
  { className: 'greeting' }, // 属性对象
  'Hello, World!'          // 子元素内容
);

JSX转换流程

JSX源代码<人写>
Babel编译器
React.createElement调用
虚拟DOM对象
React渲染引擎
真实DOM

JSX语法特性

表达式嵌入(JSX允许在大括号内嵌入任何有效的JavaScript表达式)

// 变量嵌入
const name = "React开发者";
const greeting = <h1>欢迎, {name}!</h1>;

// 函数调用
function formatName(user) {
  return user.firstName + ' ' + user.lastName; // 拼接用户姓名
}

const user = {
  firstName: '张',  // 用户姓
  lastName: '三'    // 用户名
};

const element = (
  <h1>
    Hello, {formatName(user)}!  {/* 调用函数并显示结果 */}
  </h1>
);

// 主应用组件
export default function MyApp() {
  return (
    <div>
      <h1>欢迎来到我的应用</h1>
      {/* 使用 element 变量 */}
      {element}
    </div>
  );
}

在这里插入图片描述

属性传递(JSX中的属性传递遵循特定的规则)

参考文章:React JSX属性传递规则(事件处理函数名必须用驼峰式;内联样式必须是JavaScript对象,键名用驼峰命名;className、htmlFor;自定义属性要以data-开头、动态属性绑定)

// 字符串属性
const element1 = <div className="container">内容</div>;

// 表达式属性
const isActive = true;                    // 定义状态变量
const className = isActive ? 'active' : 'inactive'; // 根据状态确定样式类名

const element2 = (
  <button 
    className={className}                 // 动态className
    onClick={() => console.log('点击')}   // 事件处理函数
    disabled={!isActive}                  // 动态禁用状态
  >
    按钮文字
  </button>
);

// 主应用组件
export default function MyApp() {
  return (
    <div>
      <h1>欢迎来到我的应用</h1>
      {/* 使用 element1 变量 */}
      {element1}
      {/* 使用 element2 变量 */}
      {element2}
    </div>
  );
}

在这里插入图片描述

条件渲染(JSX支持多种条件渲染模式)

// 用户问候组件
function UserGreeting({ isLoggedIn, user, logout }) {
  // 使用三元运算符进行条件渲染
  return (
    <div>
      {isLoggedIn ? (                     // 如果已登录
        <h1>欢迎回来, {user.name}!</h1>   // 显示欢迎信息
      ) : (                              // 如果未登录
        <h1>请先登录</h1>                // 显示登录提示
      )}
      
      {/* 使用逻辑AND运算符 */}
      {isLoggedIn && (                   // 只有登录时才显示
        <button onClick={logout}>退出</button>
      )}
    </div>
  );
}

// 主应用组件
export default function MyApp() {
  const isActive = true;                 // 登录状态
  const user = { name: "用户" };         // 用户信息
  const logout = () => console.log("退出登录"); // 退出登录函数

  return (
    <div>
      {/* 使用 UserGreeting 组件 */}
      <UserGreeting 
        isLoggedIn={isActive}            // 传递登录状态
        user={user}                      // 传递用户信息
        logout={logout}                  // 传递退出函数
      />
    </div>
  );
}

在这里插入图片描述

列表渲染(使用map方法渲染数组数据)

import React from 'react';

// TodoList 组件
function TodoList({ todos, toggleTodo }) {
  return (
    <ul>
      {todos.map((todo) => (            // 遍历待办事项数组
        <li 
          key={todo.id}                 // 为每个元素提供唯一key
          className={todo.completed ? 'completed' : ''} // 根据完成状态设置样式
        >
          <span>{todo.text}</span>      {/* 显示任务内容 */}
          <button 
            onClick={() => toggleTodo(todo.id)} // 切换完成状态的处理函数
          >
            {todo.completed ? '撤销' : '完成'} {/* 根据状态显示按钮文字 */}
          </button>
        </li>
      ))}
    </ul>
  );
}

// 主应用组件
export default function MyApp() {
  // 使用 useState 管理待办事项状态
  const [todos, setTodos] = React.useState([
    { id: 1, text: '学习 React', completed: false },
    { id: 2, text: '写代码练习', completed: true },
    { id: 3, text: '阅读文档', completed: false }
  ]);

  // 处理待办项状态切换
  const toggleTodo = (id) => {
    setTodos(todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ));
  };

  return (
    <div>
      <h2>待办事项</h2>
      {/* 使用 TodoList 组件并传递必要 props */}
      <TodoList 
        todos={todos}         // 传递待办事项数组
        toggleTodo={toggleTodo} // 传递状态切换函数
      />
    </div>
  );
}

在这里插入图片描述

JSX与传统HTML的区别

属性命名差异

HTML属性JSX属性说明
classclassName避免与JavaScript关键字冲突
forhtmlFor避免与for循环关键字冲突
tabindextabIndex采用驼峰命名法

事件处理差异

// HTML方式
// <button onclick="handleClick()">点击</button>

// JSX方式
function MyComponent() {
  const handleClick = () => {           // 定义事件处理函数
    console.log('按钮被点击了');        // 输出点击日志
  };

  return (
    <button onClick={handleClick}>      {/* 使用驼峰命名的事件属性 */}
      点击
    </button>
  );
}

JSX的优势

声明式编程

JSX采用声明式编程范式,开发者只需要描述界面应该是什么样子,而不需要关心如何操作DOM:

// 声明式:描述最终状态
function Counter() {
  const [count, setCount] = useState(0); // 状态管理Hook

  return (
    <div>
      <p>当前计数: {count}</p>           {/* 显示当前计数值 */}
      <button 
        onClick={() => setCount(count + 1)} // 点击时增加计数
      >
        增加
      </button>
    </div>
  );
}

组件化开发

JSX天然支持组件化开发模式:

// 可复用的按钮组件
function Button({ children, variant = 'primary', onClick }) {
  // 根据variant构建样式类名
  // `btn` 是基础样式类名(定义按钮基本样式)
  // `btn-${variant}` 是动态样式类名(根据传入的variant参数变化)
  // 比如当 variant="primary" 时,最终类名是 "btn btn-primary"
  const className = `btn btn-${variant}`;  

  return (
    <button 
      className={className}              // 应用样式类
      onClick={onClick}                  // 绑定点击事件
    >
      {children}                         {/* 渲染子元素 */}
    </button>
  );
}

// 使用组件
function App() {
  return (
    <div>
      {/* 主要按钮示例 */}
      <Button variant="primary" onClick={() => alert('主要按钮')}>
        主要按钮                         {/* 作为children传递 */}
      </Button>

      {/* 次要按钮示例 */}
      <Button variant="secondary" onClick={() => alert('次要按钮')}>
        次要按钮
      </Button>
    </div>
  );
}

JSX编译过程

Babel转换示例

// 原始JSX代码
const element = (
  <div className="container">
    <h1>标题</h1>
    <p>段落内容</p>
  </div>
);

// Babel编译后的代码
const element = React.createElement(
  "div",                                // 元素类型
  { className: "container" },          // 属性对象
  React.createElement("h1", null, "标题"), // 第一个子元素
  React.createElement("p", null, "段落内容") // 第二个子元素
);

编译配置

现代构建工具中的JSX配置:

// Babel配置 (.babelrc)
{
  "presets": [
    "@babel/preset-react"               // React预设,包含JSX转换
  ],
  "plugins": [
    "@babel/plugin-transform-react-jsx" // JSX转换插件
  ]
}

最佳实践

组件结构规范

// 推荐的组件结构
function UserCard({ user, onEdit, onDelete }) {
  // 1. 状态和副作用Hook
  const [isEditing, setIsEditing] = useState(false);

  // 2. 事件处理函数
  const handleEditClick = () => {       // 编辑按钮点击处理
    setIsEditing(true);                 // 进入编辑模式
    onEdit(user.id);                    // 调用父组件传入的编辑回调
  };

  const handleDeleteClick = () => {     // 删除按钮点击处理
    if (window.confirm('确定要删除吗?')) { // 确认删除操作
      onDelete(user.id);                // 调用删除回调
    }
  };

  // 3. 渲染逻辑
  return (
    <div className="user-card">
      <img src={user.avatar} alt={user.name} /> {/* 用户头像 */}
      <h3>{user.name}</h3>              {/* 用户姓名 */}
      <p>{user.email}</p>               {/* 用户邮箱 */}
      
      <div className="actions">
        <button onClick={handleEditClick}>编辑</button>
        <button onClick={handleDeleteClick}>删除</button>
      </div>
    </div>
  );
}

性能优化技巧

// 使用React.memo进行组件优化
const MemoizedUserCard = React.memo(UserCard, (prevProps, nextProps) => {
  // 自定义比较函数,只有user对象变化时才重新渲染
  return prevProps.user.id === nextProps.user.id &&
         prevProps.user.name === nextProps.user.name;
});

// 使用useCallback优化事件处理函数
function UserList({ users, onUserUpdate }) {
  const handleUserEdit = useCallback((userId) => {
    // 编辑逻辑,使用useCallback避免子组件不必要的重渲染
    onUserUpdate(userId);
  }, [onUserUpdate]);                   // 依赖数组

  return (
    <div>
      {users.map(user => (
        <MemoizedUserCard 
          key={user.id}                 // 稳定的key值
          user={user}
          onEdit={handleUserEdit}       // 优化后的回调函数
        />
      ))}
    </div>
  );
}

常见问题与解决方案

Key属性的重要性

// 错误示例:缺少key或使用不稳定的key
function BadList({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>              {/* 使用index作为key是不推荐的 */}
          {item.name}
        </li>
      ))}
    </ul>
  );
}

// 正确示例:使用稳定唯一的key
function GoodList({ items }) {
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>            {/* 使用唯一ID作为key */}
          {item.name}
        </li>
      ))}
    </ul>
  );
}

事件处理中的this绑定

// 类组件中的事件绑定
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
    
    // 方法1:在构造函数中绑定
    this.handleClick = this.handleClick.bind(this);
  }

  // 方法2:使用箭头函数
  handleClick = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <button onClick={this.handleClick}>  {/* 正确绑定的事件处理器 */}
        计数: {this.state.count}
      </button>
    );
  }
}

总结

JSX作为React生态系统的核心语法扩展,通过其声明式的特性和强大的表达能力,大大简化了前端开发的复杂度。它不仅提供了直观的组件编写方式,还通过编译时优化确保了运行时的高效性能。

理解JSX的工作原理和最佳实践,对于掌握现代React开发至关重要。随着前端生态的不断发展,JSX的应用场景也在不断扩展,从传统的Web应用到React Native移动开发,JSX都展现出了其强大的适应性和实用性。

通过合理运用JSX的各种特性,开发者能够构建出更加优雅、可维护的用户界面,这正是JSX在现代前端开发中不可替代的价值所在。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2387853.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【R语言编程绘图-箱线图】

基本箱线图绘制 使用ggplot2绘制箱线图的核心函数是geom_boxplot()。以下是一个基础示例&#xff0c;展示如何用iris数据集绘制不同物种&#xff08;Species&#xff09;的萼片长度&#xff08;Sepal.Length&#xff09;分布&#xff1a; library(ggplot2) ggplot(iris, aes(…

MongoDB索引:原理、实践与优化指南

为什么索引对数据库如此重要&#xff1f; 在现代应用开发中&#xff0c;数据库性能往往是决定用户体验的关键因素。想象一下&#xff0c;当你在电商平台搜索商品时&#xff0c;如果每次搜索都需要等待5-10秒才能看到结果&#xff0c;这种体验是多么令人沮丧。MongoDB作为最流行…

SQL实战之索引优化(单表、双表、三表、索引失效)

文章目录 单表优化双表优化三表优化结论索引失效 单表优化 总体原则&#xff1a;建立索引并合理使用&#xff0c;避免索引失效 案例说明&#xff1a;查询category_ id 为1且comments大于1的情况下,views最多的article_ id: 传统方案&#xff1a; explain select id, author_ id…

[7-1] ADC模数转换器 江协科技学习笔记(14个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 DMA&#xff08;Direct Memory Access&#xff0c;直接内存访问&#xff09;是一种硬件特性&#xff0c;它允许某些硬件子系统直接访问系统的内存&#xff0c;而无需CPU的介入。这样&#xff0c;CPU就可以处理其他任务&#xff0c;从而提高系…

阿里云 Serverless 助力海牙湾构建弹性、高效、智能的 AI 数字化平台

作者&#xff1a;赵世振、十眠、修省 “通过阿里云 Serverless 架构&#xff0c;我们成功解决了弹性能力不足、资源浪费与运维低效的痛点。SAE 的全托管特性大幅降低技术复杂度。未来&#xff0c;我们将进一步探索 Serverless 与 AI 的结合&#xff0c;为客户提供更智能的数字…

一个开源的多播放源自动采集在线影视网站

这里写自定义目录标题 欢迎使用Markdown编辑器GoFilm简介项目部署1、前置环境准备1.2 redis 配置 film-api 后端服务配置将 GoFilm 项目根目录下的 film 文件夹上传到 linux 服务器的 /opt 目录下 2. 构建运行1. docker 部署1.1 安装 docker , docker compose 环境 注意事项: 2…

深度检测与动态透明度控制 - 基于Babylon.js的遮挡检测实现解析

首先贴出实现代码&#xff1a; OcclusionFader.ts import { AbstractEngine, Material, type Behavior, type Mesh, type PBRMetallicRoughnessMaterial, type Scene } from "babylonjs/core"; import { OcclusionTester } from "../../OcclusionTester"…

docker push 报错 denied: requested access to the resource is denied

问题&#xff1a;当 docker logout -> docker login 用户登录&#xff0c;但仍然无法 docker push $ docker push <username>/nginx-custom:v1 The push refers to repository [docker.io/jagger/nginx-custom] 340e6d3ea0c7: Preparing 941dd9dd8ee4: Preparing f6…

epub→pdf | which 在线转换??好用!!

1、PDF派&#xff08;free&quick) pdf转word_pdf转换成excel_pdf转换成ppt _纬来PDF转换器 评价&#xff1a;目前使用免费&#xff0c;转化的时候有进度条提示&#xff0c;总的来说比较快&#xff0c;50mb的文件在40秒内可以转换完成&#xff0c;推荐 2、pdfconvert(free…

MySQL数据高效集成到金蝶云星空的技术分享

MySQL数据集成到金蝶云星空的技术案例分享&#xff1a;SR新建调拨单内部供应商-深圳天一 在企业信息化系统中&#xff0c;数据的高效流动和准确对接是实现业务流程自动化的关键。本文将聚焦于一个具体的系统对接集成案例——将MySQL中的数据集成到金蝶云星空&#xff0c;以支持…

Linux系统 - 基本概念

介绍一些Linux系统的基本概念 1 操作系统的核心—内核 “操作系统”通常包含两种不同含义。 1&#xff0e;指完整的软件包&#xff0c;这包括用来管理计算机资源的核心层软件&#xff0c;以及附带的所有标准软件工具&#xff0c;诸如命令行解释器、图形用户界面、文件操作工具…

PDF电子发票数据提取至Excel

声明&#xff1a;本软件是吾爱大佬th4c3y原创&#xff0c;本人只是搬运工&#xff01; 发票识别更新记录 【2025-3-14】更新 v2.0 在字段设置中新增自定义字段&#xff08;仅在 PDF 正则式接口下生效&#xff09;&#xff0c;支持自定义正则表达式或固定字符。 自定义字段会…

【身份证识别表格】把大量手机拍摄的身份证信息转换成EXCEL表格的数据,拍的身份证照片转成excel表格保存,基于WPF和腾讯OCR的实现方案

基于WPF和腾讯OCR的身份证照片转Excel方案 应用场景 ​​企业人事管理​​&#xff1a;新员工入职时批量录入数百份身份证信息&#xff0c;传统手动录入易出错且耗时。通过OCR自动提取姓名、身份证号等字段&#xff0c;生成结构化Excel表格&#xff0c;效率提升10倍以上。 ​​…

FPGA高速接口 mipi lvds cameralink hdml 千兆网 sdi

mipi: https://blog.csdn.net/SDJ_success/article/details/146541776 cameralink CameraLink协议 CameraLink协议是一种专门针对机器视觉应用领域的串行通信协议&#xff0c;它使用低压差分信号(LVDS)进行数据的传输和通信。CameraLink标准是在ChannelLink标准的基础上多加了…

Linux路径解析指南:逻辑路径 vs 实际路径详解

在 Linux 系统中&#xff0c;逻辑路径&#xff08;Logical Path&#xff09;和 实际路径&#xff08;Physical Path&#xff09;是两个不同的概念&#xff0c;主要区别在于它们如何解析文件或目录的位置。以下是详细解释&#xff1a; 目录 1. 逻辑路径&#xff08;Logical Path…

Azure 公有云基础架构与核心服务:从基础到实践指南

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 Azure 的基础架构由多个核心组件构成&#xff0c;理解这些概念是掌握其技术框架的第一步&#xff1a; 地理区域&#xff08;Geographic R…

【运维_日常报错解决方案_docker系列】一、docker系统不起来

今天忽然想起来哎&#xff0c;还有一台”尘封“着的服务器&#xff0c;好久没用了&#xff0c;就随便打开登了登&#xff0c;然后想看一下服务器上面还有正在跑着的容器服务吗&#xff0c;然后使用docker ps 发现报错了。 然后重启也是下面这个状态。 查看docker状态&#xf…

C# 数组与字符串:全面解析与应用实践

在C#编程语言中&#xff0c;数组和字符串是两种最基础也是最重要的数据类型。无论是简单的控制台应用程序&#xff0c;还是复杂的企业级系统&#xff0c;数组和字符串都扮演着不可或缺的角色。本文将全面深入地探讨C#中数组和字符串的特性、使用方法、性能考量以及实际应用场景…

‌AT2659S射频前端芯片技术解析:L1频段低噪声高增益GNSS信号放大

以下是关于‌AT2659S L1频段卫星导航射频前端芯片‌的客观描述&#xff0c;严格基于用户提供的原始信息&#xff0c;采用分享式表述&#xff0c;保持参数和核心内容不变&#xff1a; AT2659S芯片概述‌ AT2659S是一款基于SiGe工艺的射频前端芯片&#xff0c;专为L1频段&#…

ROS2学习(15)------ROS2 TF2 机器人坐标系管理器

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 ROS版本&#xff1a;2 在 ROS 2 中&#xff0c;TF2&#xff08;Transform Library, v2&#xff09; 是一个非常核心的工具库&#xff0c;用于管理多个坐标系之间的 变换关系&#xff08;tran…