pin_drop当前位置:知识文库 ❯ 图文

框架集成:02 HTML与React集成 - 详细教程与实战指南

一、教程简介

React是Meta(原Facebook)开发的JavaScript库,是目前使用最广泛的前端框架之一。React通过JSX语法和组件化模型,将HTML的编写方式从静态标记转变为动态、可组合的UI构建方式。本教程将介绍React的基础概念、CDN引入方式、createElement API、React渲染流程以及第一个React组件的创建,帮助你理解React如何与HTML集成工作。


二、React简介

React的核心思想是 UI = f(state),即UI是状态的函数。给定相同的状态,React总是渲染相同的UI。这种声明式的编程模型让开发者只需关注"UI应该是什么样子",而不必手动操作DOM来更新界面。

React的三大核心原则:

  • 声明式:描述UI应该呈现的样子,React负责更新DOM

  • 组件化:将UI拆分为独立、可复用的组件

  • 一次学习,随处编写:React不仅用于Web,还可用于React Native开发移动应用


三、CDN引入方式

最简单的React入门方式是通过CDN引入。React提供了UMD构建版本,可以直接通过script标签引入使用。

方式一:开发版本(含警告和调试信息)

代码示例

<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

方式二:生产版本(压缩优化)

代码示例

<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>

方式三:引入Babel(支持JSX)

代码示例

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

<!-- JSX代码需要指定type="text/babel" -->
<script type="text/babel">
  const element = <h1>Hello, React!</h1>;
</script>

提示:Babel浏览器版本仅用于学习和原型开发,生产环境应使用构建工具预编译。


四、createElement与HTML

React.createElement 是React创建虚拟DOM元素的基础API,它是JSX编译后的实际输出。

API签名

代码示例

React.createElement(
  type,        // 标签名(如'div')、组件函数或类
  props,       // 属性对象(如{className: 'active', id: 'main'})
  ...children  // 子元素(字符串、元素或数组)
)

HTML与createElement对照

对比项 HTML写法 createElement写法
容器元素 <div className="container"> React.createElement('div', { className: 'container' })
标题元素 <h1 id="title">标题</h1> React.createElement('h1', { id: 'title' }, '标题')
段落元素 <p>段落内容</p> React.createElement('p', null, '段落内容')
按钮事件 <button onClick={handleClick}>点击</button> React.createElement('button', { onClick: handleClick }, '点击')

五、React渲染流程

React的渲染流程从 createRoot 开始,经过虚拟DOM创建、协调(Reconciliation)和提交(Commit)三个阶段:

  • 状态变更:用户交互或数据变化触发状态更新

  • 创建新VDOM:根据新状态生成新的虚拟DOM树

  • Diff比较:对比新旧虚拟DOM,计算最小差异

  • 计算变更:确定需要更新的具体DOM操作

  • 更新DOM:将变更批量应用到真实DOM


六、ReactDOM.createRoot

React 18引入了新的 createRoot API,替代了旧的 ReactDOM.render

旧API(React 17及之前)

代码示例

import ReactDOM from 'react-dom';

// 旧方式:直接render
ReactDOM.render(
  <App />,
  document.getElementById('root')
);

新API(React 18+)

代码示例

import { createRoot } from 'react-dom/client';

// 新方式:先创建root,再render
const root = createRoot(document.getElementById('root'));
root.render(<App />);

// 卸载
root.unmount();

createRoot的优势

  • 并发特性:支持React 18的并发渲染(Concurrent Rendering)

  • 自动批处理:多次状态更新自动合并为一次渲染

  • 过渡更新:支持startTransition等新API

  • Suspense:更好的Suspense支持


七、React与DOM的关系

React维护一个虚拟DOM树,通过diff算法计算最小变更,然后批量更新真实DOM。当React通过createRoot挂载到某个DOM节点后,该节点及其子节点的管理权就交给React了。开发者不应直接操作这些DOM节点。

代码示例

// React管理的DOM区域
<div id="root">
  <!-- 这里的内容由React完全管理 -->
  <!-- 不要直接操作这里的DOM -->
</div>

// React不管理的DOM区域
<header id="site-header">
  <!-- 这里的内容React不管,可以自由操作 -->
</header>

八、第一个React组件

综合以上知识,创建一个完整的React待办事项组件示例。该组件展示了状态管理、事件处理、条件渲染、列表渲染等核心概念:

代码示例

const { useState } = React;

// TodoItem 子组件
function TodoItem(props) {
  return React.createElement('li', {
    className: 'todo-item' + (props.done ? ' done' : '')
  },
    React.createElement('div', {
      className: 'todo-checkbox' + (props.done ? ' checked' : ''),
      onClick: function() { props.onToggle(props.id); }
    }),
    React.createElement('span', { className: 'todo-text' }, props.text),
    React.createElement('button', {
      className: 'todo-delete',
      onClick: function() { props.onDelete(props.id); }
    }, '\u00d7')
  );
}

// TodoApp 主组件
function TodoApp() {
  var [todos, setTodos] = useState([
    { id: 1, text: '学习React基础', done: false },
    { id: 2, text: '理解createElement', done: true },
    { id: 3, text: '掌握渲染流程', done: false }
  ]);
  var [inputText, setInputText] = useState('');
  var [filter, setFilter] = useState('all');

  function addTodo() {
    var text = inputText.trim();
    if (!text) return;
    setTodos(function(prev) {
      return prev.concat([{ id: Date.now(), text: text, done: false }]);
    });
    setInputText('');
  }

  function toggleTodo(id) {
    setTodos(function(prev) {
      return prev.map(function(t) {
        return t.id === id ? Object.assign({}, t, { done: !t.done }) : t;
      });
    });
  }

  function deleteTodo(id) {
    setTodos(function(prev) {
      return prev.filter(function(t) { return t.id !== id; });
    });
  }

  // 渲染待办列表...
}

九、浏览器兼容性

特性 Chrome Firefox Safari Edge 说明
React 18 60+ 60+ 12+ 79+ 需要ES2015+支持
createRoot API 60+ 60+ 12+ 79+ React 18新API
useState Hook 60+ 60+ 12+ 79+ 需要ES2015+支持
ES Modules 61+ 60+ 11+ 16+ 构建工具使用
Proxy对象 49+ 18+ 10+ 12+ 部分内部机制依赖
requestIdleCallback 47+ 55+ 不支持 79+ 并发模式可选依赖

十、注意事项与最佳实践

  • CDN方式仅用于学习:生产环境应使用Vite、Webpack等构建工具,支持JSX编译、代码分割、Tree Shaking等优化

  • 不要直接操作React管理的DOM:React通过虚拟DOM管理更新,直接操作DOM会导致状态不一致

  • 使用key属性:列表渲染时必须为每个元素提供唯一的key,帮助React高效diff

  • 状态更新是异步的:调用setState后无法立即获取最新值,需要使用回调或useEffect

  • 组件名首字母大写:React区分原生HTML标签(小写)和自定义组件(大写首字母)

  • 单向数据流:数据从父组件流向子组件,通过props传递,子组件通过回调通知父组件


十一、代码规范示例

状态驱动 vs 直接操作DOM

代码示例

// 不推荐:直接操作React管理的DOM
function MyComponent() {
  const ref = useRef();
  const handleClick = () => {
    // 直接操作DOM,破坏React的数据流
    ref.current.style.color = 'red';
  };
}

// 推荐:通过状态驱动UI更新
function MyComponent() {
  const [isActive, setIsActive] = useState(false);
  return React.createElement('div', {
    style: { color: isActive ? 'red' : 'black' },
    onClick: () => setIsActive(true)
  }, '点击变红');
}

列表渲染key的使用

代码示例

// 不推荐:缺少key的列表渲染
users.map(function(user) {
  return React.createElement('li', null, user.name);
});

// 推荐:使用唯一key
users.map(function(user) {
  return React.createElement('li', { key: user.id }, user.name);
});

// 不推荐:使用index作为key(当列表会变化时)
items.map(function(item, index) {
  return React.createElement('li', { key: index }, item.text);
});

// 推荐:使用稳定的唯一标识
items.map(function(item) {
  return React.createElement('li', { key: item.id }, item.text);
});

十二、常见问题与解决方案

常见问题

CDN引入React时,为什么需要crossorigin属性?

crossorigin属性允许浏览器获取跨域脚本的错误堆栈信息,便于调试。不加此属性,React的错误边界和开发工具可能无法正常报告错误。

React.createElement和JSX有什么区别?

JSX是语法糖,编译后就是createElement调用。JSX更易读写,createElement是底层API。实际开发中使用JSX,了解createElement有助于理解React的工作原理。

为什么React 18要使用createRoot替代ReactDOM.render?

createRoot启用了React 18的并发特性,包括自动批处理、startTransition、Suspense等。旧的ReactDOM.render仍可使用但会失去这些新特性,且会在控制台产生警告。

React组件的render方法为什么不能直接修改state?

render应该是纯函数,给定相同的props和state,总是返回相同的UI。如果在render中修改state,会触发无限循环渲染,导致性能问题和栈溢出。

一个页面可以有多个React根吗?

可以。一个页面可以有多个createRoot挂载点,每个根独立管理自己的组件树。这在渐进式迁移旧项目时很有用。


十三、总结

本教程介绍了React与HTML集成的基础知识。React通过createElement API创建虚拟DOM元素,通过createRoot将虚拟DOM渲染到真实DOM中。React的渲染流程包括状态变更、创建新虚拟DOM、Diff比较和DOM更新四个步骤。理解React与DOM的关系至关重要——React管理的DOM区域不应直接操作,而应通过状态驱动UI更新。通过CDN方式可以快速入门React,但生产环境应使用构建工具以获得JSX支持和更好的优化。在下一教程中,我们将深入学习JSX语法及其与HTML的关系。

标签: React createElement 虚拟DOM createRoot React组件 CDN引入 声明式编程

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: 框架集成:01 HTML与前端框架概述 - 详细教程与实战指南 下一篇: 框架集成:03 React JSX与HT - 详细教程与实战指南

poll相关推荐