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对照
五、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; });
});
}
// 渲染待办列表...
}九、浏览器兼容性
十、注意事项与最佳实践
-
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的关系。
本文涉及AI创作
内容由AI创作,请仔细甄别