<!DOCTYPE html><html lang="zh" data-theme="dark"><head><meta charset="utf-8"><meta name="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>IBM 全栈开发【4】:React 创建前端应用 · Cytrogen 的个人博客</title><meta name="description" content="本文是 IBM 全栈开发课程的第四篇学习笔记,系统性地介绍了如何使用 React 和 ES6 构建前端应用。内容从 React 的基础概念(如JSX、组件化)和 ES6 核心语法(箭头函数、类)讲起,深入探讨了组件的状态(state)与属性(props)、完整的生命周期、父子组件间的数据通信,以及如何使用 Hooks 为函数式组件添加状态。此外,笔记还涵盖了 React 表单处理和使用 Redux 进行全局状态管理等进阶主题。这篇笔记为 React 初学者提供了一份从入门到进阶的完整学习路径和知识点梳理。"><link rel="icon" href="../favicon.png"><link rel="canonical" href="https://cytrogen.icu/posts/d011.html"><link rel="webmention" href="https://webmention.io/cytrogen.icu/webmention"><link rel="me" href="https://m.otter.homes/@Cytrogen"><link rel="me" href="https://github.com/cytrogen"><meta name="fediverse:creator" content="@Cytrogen@m.otter.homes"><link rel="preload" href="../fonts/opensans-regular-latin.woff2" as="font" type="font/woff2" crossorigin="anonymous"><style>@font-face {
font-family: 'Open Sans';
src: url('../fonts/opensans-regular-latin.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
size-adjust: 107%;
ascent-override: 97%;
descent-override: 25%;
line-gap-override: 0%;
}
</style><script>(function() {
try {
// 优先级:用户选择 > 系统偏好 > 默认浅色
const saved = localStorage.getItem('theme');
const theme = saved ||
(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', theme);
document.documentElement.style.colorScheme = theme;
} catch (error) {
// 失败时使用默认主题,不阻塞渲染
document.documentElement.setAttribute('data-theme', 'light');
}
})();
</script><link rel="stylesheet" href="../css/ares.css"><script data-netlify-skip-bundle="true">(function() {
document.addEventListener('DOMContentLoaded', function() {
const theme = document.documentElement.getAttribute('data-theme');
const pageWrapper = document.getElementById('page-wrapper');
if (pageWrapper && theme) {
pageWrapper.setAttribute('data-theme', theme);
}
});
})();
</script><!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-math@4.0.0/dist/style.css">
<!-- hexo injector head_end end --><meta name="generator" content="Hexo 8.1.1"><link rel="alternate" href="atom.xml" title="Cytrogen 的个人博客" type="application/atom+xml">
</head><body><div id="page-wrapper"><a class="skip-link" href="#main-content">跳到主要内容</a><div class="wrap"><header><a class="logo-link" href="../index.html"><img src="../favicon.png" alt="logo"></a><div class="h-card visually-hidden"><img class="u-photo" src="https://cytrogen.icu/favicon.png" alt="Cytrogen"><a class="p-name u-url u-uid" href="https://cytrogen.icu">Cytrogen</a><p class="p-note">Cytrogen 的个人博客,Cytrogen's Blog</p><a class="u-url" rel="me noopener" target="_blank" href="https://m.otter.homes/@Cytrogen">Mastodon</a><a class="u-url" rel="me noopener" target="_blank" href="https://github.com/cytrogen">GitHub</a></div><nav class="site-nav"><div class="nav-main"><div class="nav-primary"><ul class="nav-list hidden-mobile"><li class="nav-item"><a class="nav-link" href="../index.html">首页</a></li></ul><div class="nav-tools"><div class="language-menu"><button class="language-toggle" type="button"><svg class="icon icon-globe" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855A7.97 7.97 0 0 0 5.145 4H7.5V1.077zM4.09 4a9.267 9.267 0 0 1 .64-1.539 6.7 6.7 0 0 1 .597-.933A7.025 7.025 0 0 0 2.255 4H4.09zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a6.958 6.958 0 0 0-.656 2.5h2.49zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5H4.847zM8.5 5v2.5h2.99a12.495 12.495 0 0 0-.337-2.5H8.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5H4.51zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5H8.5zM5.145 12c.138.386.295.744.468 1.068.552 1.035 1.218 1.65 1.887 1.855V12H5.145zm.182 2.472a6.696 6.696 0 0 1-.597-.933A9.268 9.268 0 0 1 4.09 12H2.255a7.024 7.024 0 0 0 3.072 2.472zM3.82 11a13.652 13.652 0 0 1-.312-2.5h-2.49c.062.89.291 1.733.656 2.5H3.82zm6.853 3.472A7.024 7.024 0 0 0 13.745 12H11.91a9.27 9.27 0 0 1-.64 1.539 6.688 6.688 0 0 1-.597.933zM8.5 12v2.923c.67-.204 1.335-.82 1.887-1.855A7.97 7.97 0 0 0 10.855 12H8.5zm3.68-1h2.146c.365-.767.594-1.61.656-2.5h-2.49a13.65 13.65 0 0 1-.312 2.5zm2.802-3.5a6.959 6.959 0 0 0-.656-2.5H12.18c.174.782.282 1.623.312 2.5h2.49zM11.27 2.461c.247.464.462.98.64 1.539h1.835a7.024 7.024 0 0 0-3.072-2.472c.218.284.418.598.597.933zM10.855 4a7.966 7.966 0 0 0-.468-1.068C9.835 1.897 9.17 1.282 8.5 1.077V4h2.355z"></path></svg><span>中文</span></button><div class="language-dropdown"></div></div></div><div class="nav-controls"><div class="more-menu hidden-mobile"><button class="more-toggle" type="button"><span>更多</span><svg class="icon icon-chevron-down" width="12" height="12" viewBox="0 0 12 12" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 8.825c-.2 0-.4-.1-.5-.2l-3.3-3.3c-.3-.3-.3-.8 0-1.1s.8-.3 1.1 0l2.7 2.7 2.7-2.7c.3-.3.8-.3 1.1 0s.3.8 0 1.1l-3.3 3.3c-.1.1-.3.2-.5.2z"></path></svg></button><div class="more-dropdown"><ul class="dropdown-list"><li class="dropdown-item"><a class="nav-link" href="../archives/index.html">归档</a></li><li class="dropdown-item"><a class="nav-link" href="../categories/index.html">分类</a></li><li class="dropdown-item"><a class="nav-link" href="../tags/index.html">标签</a></li><li class="dropdown-item"><a class="nav-link" href="../about/index.html">关于</a></li><li class="dropdown-item"><a class="nav-link" href="../sitemap/index.html">领地地图</a></li></ul></div></div><div class="theme-switcher"><button class="theme-toggle" type="button" role="switch" aria-pressed="false" aria-label="切换主题"><div class="theme-icon moon-icon"><svg class="icon icon-moon" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z"></path></svg></div><div class="theme-icon sun-icon"><svg class="icon icon-sun" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z"></path></svg></div></button></div><details class="mobile-menu-details hidden-desktop"><summary class="hamburger-menu" aria-label="nav.menu"><svg class="icon icon-bars" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"></path></svg><span class="menu-text">nav.menu</span></summary><div class="mobile-menu-dropdown"><ul class="mobile-nav-list"><li class="mobile-nav-item"><a class="mobile-nav-link" href="../index.html">首页</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../archives/index.html">归档</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../categories/index.html">分类</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../tags/index.html">标签</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../about/index.html">关于</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../sitemap/index.html">领地地图</a></li></ul></div></details></div></div></div></nav></header><main class="container" id="main-content" tabindex="-1"><div class="post"><article class="post-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="author-avatar u-photo" src="../favicon.png" alt="Cytrogen"><span class="p-name">Cytrogen</span><a class="u-url" href="https://cytrogen.icu">https://cytrogen.icu</a></div><a class="post-permalink u-url u-uid visually-hidden" href="https://cytrogen.icu/posts/d011.html">永久链接</a><div class="p-summary visually-hidden"><p>近期在学习 IBM 全栈应用开发微学士课程,故此记录学习笔记。</p></div><div class="visually-hidden"><a class="p-category" href="../categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/">编程笔记</a><a class="p-category" href="../tags/IBM/">IBM</a><a class="p-category" href="../tags/React-js/">React.js</a></div><h1 class="post-title p-name">IBM 全栈开发【4】:React 创建前端应用</h1><div class="post-info"><time class="post-date dt-published" datetime="2024-01-18T05:40:13.000Z">1/18/2024</time><time class="dt-updated visually-hidden" datetime="2026-02-09T17:16:54.717Z"></time></div><div class="post-content e-content"><html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程,故此记录学习笔记。</p>
<span id="more"></span>
<h1 id="1-使用react和es6创建前端应用"><a class="markdownIt-Anchor" href="#1-使用react和es6创建前端应用"></a> 1. 使用 React 和 ES6 创建前端应用</h1>
<h2 id="11-前端框架"><a class="markdownIt-Anchor" href="#11-前端框架"></a> 1.1. 前端框架</h2>
<p>前端框架用于创建可连接服务器的动态客户端应用程序。它们通常是开源项目:</p>
<ul>
<li>Angular</li>
<li>React</li>
<li>Vue</li>
</ul>
<h4 id="111-angular"><a class="markdownIt-Anchor" href="#111-angular"></a> 1.1.1. Angular</h4>
<p>Angular 是一个开源的框架,由谷歌维护。它基于 HTML 和 JavaScript,并且易于实现。</p>
<p>Angular 使用指令来使 HTML 更加动态,所有指令都可用于包含库的 HTML。</p>
<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><!DOCTYPE <span class="keyword">html</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">body</span> <span class="attr">ng-app</span>></span></span><br><span class="line"> Company Name: <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">ng-model</span>=<span class="string">"comp_name"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">br</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span> <span class="attr">ng-bind</span>=<span class="string">"comp_name"</span>></span><span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></tbody></table></figure>
<h4 id="112-vue"><a class="markdownIt-Anchor" href="#112-vue"></a> 1.1.2. Vue</h4>
<p>Vue 是一个开源的前端框架,它使用虚拟 DOM 来实现高性能,HTML 被视为一个完整的对象。Vue 非常轻量级、渲染速度快、易于学习。</p>
<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>VueJS Introduction<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdn.jsdelivr.net/.../vue.js"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"intro"</span> <span class="attr">style</span>=<span class="string">"text-align: center;"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">h5</span>></span></span><br><span class="line"> {{ message }}</span><br><span class="line"> <span class="tag"></<span class="name">h5</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">var</span> vue_det = <span class="keyword">new</span> <span class="title class_">Vue</span>({</span></span><br><span class="line"><span class="language-javascript"> <span class="attr">el</span>: <span class="string">"#intro"</span>,</span></span><br><span class="line"><span class="language-javascript"> <span class="attr">data</span>: {</span></span><br><span class="line"><span class="language-javascript"> <span class="attr">message</span>: <span class="string">"This is a Vue HTML"</span></span></span><br><span class="line"><span class="language-javascript"> }</span></span><br><span class="line"><span class="language-javascript"> });</span></span><br><span class="line"><span class="language-javascript"> </span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></tbody></table></figure>
<h4 id="113-react"><a class="markdownIt-Anchor" href="#113-react"></a> 1.1.3. React</h4>
<p>React 是一个用于构建客户端动态网络应用程序的框架,使用动态数据绑定和虚拟 DOM 来扩展 HTML 语法,而不需要编写额外的代码,并保持用户界面元素与应用程序状态的同步。</p>
<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">h1</span>></span></span><br><span class="line"> Watson Author Finder</span><br><span class="line"> <span class="tag"></<span class="name">h1</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span></span><br><span class="line"> Please write your details</span><br><span class="line"> <span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">form</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"name"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"age"</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">form</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></tbody></table></figure>
<p>React 使用 JavaScript XML 这种类似于 HTML 的特殊语言来创建用户界面,其可被 Babel 编译器编译为 JavaScript。</p>
<p>JavaScript XML 要嵌入在特殊的脚本标签中,其中的 <code>type</code> 属性指定了需要 Babel 的内容。</p>
<blockquote>
<p>用于构建 React 应用程序的三个重要软件包:</p>
<ul>
<li>React 包:保存组件以及其状态和属性的 React 源代码</li>
<li>ReactDOM 包:React 和 DOM 之间的粘合剂</li>
<li>Babel 编译器:将 JavaScript XML 编译为 JavaScript</li>
</ul>
</blockquote>
<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"> <span class="comment"><!-- Load React API --></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://unpkg.com/react@16/umd/react.production.min.js"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="comment"><!-- Load React DOM --></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="comment"><!-- Load Babel Compiler --></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://unpkg.com/babel-standalone@6.15.0/babel.min.js"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> </span><br><span class="line"> <span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"comp1"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/babel"</span>></span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">class</span> <span class="title class_">Mycomp</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span></span><br><span class="line"><span class="language-javascript"> <span class="comment">// override the render method</span></span></span><br><span class="line"><span class="language-javascript"> <span class="title function_">render</span>(<span class="params"></span>) {</span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">h1</span>></span>This is my own component named {this.props.name}<span class="tag"></<span class="name">h1</span>></span></span>;</span></span><br><span class="line"><span class="language-javascript"> }</span></span><br><span class="line"><span class="language-javascript"> }</span></span><br><span class="line"><span class="language-javascript"> <span class="title class_">ReactDOM</span>.<span class="title function_">render</span>(<span class="language-xml"><span class="tag"><<span class="name">Mycomp</span> <span class="attr">name</span>=<span class="string">"myBrandNewComp"</span>)/></span></span>, <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"comp1"</span>));</span></span><br><span class="line"><span class="language-javascript"> </span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>React 组件要在 <code><script></code> 标签中定义,<code>type</code> 属性的类型需要设置为 <code>text/babel</code>,以便 Babel 编译器将其编译为 JavaScript
<ul>
<li>定义的组件为 <code>Mycomp</code>,继承自 <code>React.Component</code>,并重写了 <code>render()</code> 方法</li>
</ul>
</li>
<li><code>ReactDOM.render()</code> 方法用于渲染组件,并指定组件名称、HTML 标签和要设置的任何属性(该例子中就设置了 <code>name</code> 属性)</li>
<li>组件需要被指定呈现在 HTML 页面的哪个位置(该例子中就是 <code>comp1</code>)</li>
</ul>
<p>Facebook 提供了一个名为「Create React App」的工具,可以简化创建 React 应用程序的过程。</p>
<p>如果已安装 Node.JS,就可以运行以下命令来安装 Create React App:</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx create-react-app my-app</span><br></pre></td></tr></tbody></table></figure>
<p>当运行完上述命令后,系统会自动创建一个包含所有必要文件的目录结构。该目录结构包含创建和运行 React 应用程序所需的所有文件。</p>
<ul>
<li><code>src</code> 目录是我们需要修改的主要目录
<ul>
<li><code>App.js</code> 文件是我们要添加到 HTML 页面的 React 根组件</li>
<li><code>index.js</code> 文件将应用程序添加到 HTML 页面</li>
</ul>
</li>
</ul>
<h2 id="12-es6"><a class="markdownIt-Anchor" href="#12-es6"></a> 1.2. ES6</h2>
<p>ES6 的全程为 ECMAScript 6,制定了广泛的全球信息和通信技术标准。</p>
<p>JavaScript 遵循 ECMAScript 6 标准(2015 年),其最主要的更改是:</p>
<ul>
<li><code>let</code></li>
<li><code>const</code></li>
<li>箭头函数</li>
<li>Promise 构造函数</li>
<li>类</li>
</ul>
<h4 id="121-let和const"><a class="markdownIt-Anchor" href="#121-let和const"></a> 1.2.1. <code>let</code> 和 <code>const</code></h4>
<p><code>let/const</code> 和 <code>var</code> 不同:</p>
<ul>
<li><code>var</code> 声明的变量的作用域是全局的。这很有挑战性,尤其是在大型项目中,代表着有许多变量需要维护</li>
<li><code>let</code> 可以将变量的作用域限制在声明变量的代码块中 <figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">let</span> num = <span class="number">5</span>;</span><br><span class="line"> num = <span class="number">6</span>;</span><br><span class="line">}</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num); <span class="comment">// will throw an error</span></span><br></pre></td></tr></tbody></table></figure>
</li>
<li><code>const</code> 声明的变量的值不能被修改 <figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> num = <span class="number">5</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num);</span><br><span class="line">num = <span class="number">6</span>; <span class="comment">// will throw an error</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num);</span><br></pre></td></tr></tbody></table></figure>
</li>
</ul>
<h4 id="122-箭头函数"><a class="markdownIt-Anchor" href="#122-箭头函数"></a> 1.2.2. 箭头函数</h4>
<p>箭头函数允许函数像变量一样声明,这是一种更简洁的函数声明方式。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// how a function was written in the older ES5 JavaScript</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">sayHello</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"ES5 function - Hello world!"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// arrow function in ES6</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">sayHello</span> = (<span class="params"></span>)=> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"ES6 function - Hello world!"</span>);</span><br></pre></td></tr></tbody></table></figure>
<p>箭头函数可以被调用,并可以作为回调的参数传递。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">sayHello</span> = (<span class="params"></span>)=> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Hello world!"</span>);</span><br><span class="line"><span class="built_in">setTimeout</span>(sayHello, <span class="number">1000</span>);</span><br></pre></td></tr></tbody></table></figure>
<p>箭头函数也可以像普通函数一样接受参数。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// takes one parameter</span></span><br><span class="line"><span class="comment">// brackets are not mandatory</span></span><br><span class="line"><span class="comment">// because the code returns a value, it must be in curly brackets</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">oneParamArrowFunc</span> = name => {<span class="keyword">return</span> <span class="string">"hello "</span> + name};</span><br><span class="line"></span><br><span class="line"><span class="comment">// function brackets must be put around the parameters list</span></span><br><span class="line"><span class="comment">// does not need curly brackets because it only has one line of code and returns nothing</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">twoParamsArrowFuncWithoutReturn</span> = (<span class="params">first, last</span>) => <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"hello "</span> + first + <span class="string">" "</span> + last);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">twoParamsArrowFuncWithReturn</span> = (<span class="params">first, last</span>) => {<span class="keyword">return</span> <span class="string">"hello "</span> + first + <span class="string">" "</span> + last};</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">twoParamsTwoLinesArrowFunc</span> = (<span class="params">first, last</span>) => {</span><br><span class="line"> <span class="keyword">const</span> greeting = <span class="string">"hello "</span>;</span><br><span class="line"> <span class="keyword">return</span> greeting + <span class="string">" "</span> + first + <span class="string">" "</span> + last;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<h4 id="123-promise"><a class="markdownIt-Anchor" href="#123-promise"></a> 1.2.3. Promise</h4>
<p>Promise 对象表示了一个异步操作的最终完成或失败,以及其返回值。每当你调用异步操作时,Promise 会处于 pending(挂起)状态;当操作成功地执行时,Promise 会处于 fulfilled(履行)状态;当操作失败时,Promise 会处于 rejected(拒绝)状态。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title function_">promiseArgument</span> = (<span class="params">resolve, reject</span>) => {</span><br><span class="line"> <span class="built_in">setTimeout</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">let</span> currTime = <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getTime</span>();</span><br><span class="line"> <span class="keyword">if</span> (currTime % <span class="number">2</span> === <span class="number">0</span>) {</span><br><span class="line"> <span class="title function_">resolve</span>(<span class="string">"Success!"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="title function_">reject</span>(<span class="string">"Failed!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }, <span class="number">2000</span>);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> myPromise = <span class="keyword">new</span> <span class="title class_">Promise</span>(promiseArgument);</span><br></pre></td></tr></tbody></table></figure>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> myPromise = <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> <span class="built_in">setTimeout</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">let</span> currTime = <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getTime</span>();</span><br><span class="line"> <span class="keyword">if</span> (currTime % <span class="number">2</span> === <span class="number">0</span>) {</span><br><span class="line"> <span class="title function_">resolve</span>(<span class="string">"Success!"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="title function_">reject</span>(<span class="string">"Failed!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }, <span class="number">2000</span>);</span><br><span class="line">});</span><br></pre></td></tr></tbody></table></figure>
<blockquote>
<p>以上两种写法是等价的。</p>
</blockquote>
<h4 id="124-类"><a class="markdownIt-Anchor" href="#124-类"></a> 1.2.4. 类</h4>
<p>ES6 中的类使面向对象编程在 JavaScript 中更加容易。类创建了对象的模板,且建立在原型(即 prototype,是所有 JavaScript 对象的属性,包括函数,而函数可用于创建对象实例)的基础上。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">name, age</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> person1 = <span class="title class_">Person</span>(<span class="string">"John"</span>, <span class="number">20</span>);</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li><code>this</code> 指代的是当前对象</li>
<li>类的概念是在函数原型的前提下建立的,目的是将面向对象编程扩展到 JavaScript 中</li>
</ul>
<p>构造函数(constructor)是一个特殊的函数,用于创建一个类对象:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Rectangle</span> {</span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params">height, width</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">height</span> = height;</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">width</span> = width;</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> myRectangle = <span class="keyword">new</span> <span class="title class_">Rectangle</span>(<span class="number">10</span>, <span class="number">5</span>);</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>使用 <code>new</code> 关键字就可以创建一个类的实例</li>
</ul>
<p>在 JavaScript ES6 中,类可以继承自其他类。继承其他类的类被称为子类(subclass),而超类(superclass)是被子类继承的类。子类会继承超类的所有属性和方法。</p>
<p>子类具有特殊权限,能够使用 <code>super()</code> 方法来调用超类的构造函数。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Square</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Rectangle</span> {</span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params">height, width</span>) {</span><br><span class="line"> <span class="keyword">if</span> (height === width) {</span><br><span class="line"> <span class="variable language_">super</span>(height, width);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// if the height is not the same as the width specified,</span></span><br><span class="line"> <span class="comment">// the width will become equal to the height</span></span><br><span class="line"> <span class="variable language_">super</span>(height, height);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> mySquare = <span class="keyword">new</span> <span class="title class_">Square</span>(<span class="number">5</span>, <span class="number">5</span>);</span><br></pre></td></tr></tbody></table></figure>
<h2 id="13-jsx"><a class="markdownIt-Anchor" href="#13-jsx"></a> 1.3. JSX</h2>
<p>JSX 是 JavaScript XML 或 JavaScript Syntax Extension 的缩写,是一种类似于 React 使用的 XML 或 HTML 类语法,用于创建 React 元素。 JSX 允许 XML 或 HTML 类文本与 JavaScript 或 React 代码并存。</p>
<p>JSX 使用预处理器将 JavaScript 文件中的 HTML 类文本转换为标准的 JavaScript 对象,例如转译器或编译器(比方说 Babel)。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> el1 = <span class="language-xml"><span class="tag"><<span class="name">h1</span>></span>This is a sample JSX code snippet<span class="tag"></<span class="name">h1</span>></span></span></span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>JSX 代码的语法就像是 HTML 使用了类似 JavaScript 的变量</li>
</ul>
<h4 id="131-react代码例子"><a class="markdownIt-Anchor" href="#131-react代码例子"></a> 1.3.1. React 代码例子</h4>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">App</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">p</span>></span>This is a sample list<span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">ul</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">li</span>></span>List item no. 1<span class="tag"></<span class="name">li</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">li</span>></span>List item no. 2<span class="tag"></<span class="name">li</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">ul</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>而这是普通的 JavaScript 代码:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">App</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title class_">React</span>.<span class="title function_">createElement</span>(</span><br><span class="line"> <span class="string">"div"</span>,</span><br><span class="line"> <span class="literal">null</span>,</span><br><span class="line"> <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">"p"</span>, <span class="literal">null</span>, <span class="string">"This is a sample list"</span>),</span><br><span class="line"> <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">"ul"</span>, <span class="literal">null</span>,</span><br><span class="line"> <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">"li"</span>, <span class="literal">null</span>, <span class="string">"List item no. 1"</span>),</span><br><span class="line"> <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">"li"</span>, <span class="literal">null</span>, <span class="string">"List item no. 2"</span>))</span><br><span class="line"> );</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>可以看出来,如果没有 JSX,React 代码将不得不使用大量嵌套来编写,这会导致代码变得难以阅读和维护。</p>
<h4 id="132-组件"><a class="markdownIt-Anchor" href="#132-组件"></a> 1.3.2. 组件</h4>
<p>组件(component)是 React 的核心构件,是一个可重用的代码块,用于创建用户界面。组件可以是函数或类,它们接受输入并返回 React 元素。</p>
<p>组件可以拥有自己的状态,这些状态是描述了组件行为的对象。有状态的组件的类型为类,而无状态的组件的类型为函数。</p>
<p>React 组件通过三个概念实现这些功能:</p>
<ol>
<li>属性(property):用于从父组件向子组件传递数据</li>
<li>事件(event):使组件能够管理 DOM 事件和用户在系统上交互的动作</li>
<li>状态(state):根据组件的当前状态更新用户界面</li>
</ol>
<p>React 应用程序是一颗组件树:根组件就像一个容器,它包含了所有其他组件。 所有组件的名称,无论是函数还是类,都必须以大写字母开头。组件可以通过使用 <code>className</code> 属性和 CSS 来进行样式化。</p>
<p>组件类型:</p>
<ol>
<li>
<p>函数式组件通过编写 JavaScript 函数来创建,可以接受也可以不接受数据作为参数,返回 JSX 函数。它们本身没有状态或生命周期方法,因此也被称为无状态组件,但是可以通过实现 React Hooks 来添加这些功能。</p>
<ul>
<li>React Hook 是 React 的一项新功能,它能让你在不编写类的情况下使用 React 的特性</li>
<li>生命周期方法(lifecycle methods)是 React 内置的方法,可以在 DOM 中的整个持续时间内对组件进行操作</li>
</ul>
<p>函数式组件用于显示易于阅读、调试和测试的静态数据。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">Democomponent</span> = (<span class="params"></span>) => {</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">h1</span>></span>welcome Message!<span class="tag"></<span class="name">h1</span>></span></span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>当组件有属性但生命周期不需要管理时最有用。</p>
<p>函数式组件可以接受用户自定义的属性作为参数:</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">App</span>(<span class="params">props</span>) { <span class="comment">// props passed as a function parameter</span></span><br><span class="line"> <span class="keyword">const</span> compStyle = {</span><br><span class="line"> <span class="attr">color</span>: props.<span class="property">color</span>,</span><br><span class="line"> <span class="attr">fontSize</span>: props.<span class="property">size</span> + <span class="string">'px'</span></span><br><span class="line"> };</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">span</span> <span class="attr">style</span>=<span class="string">{compStyle}</span>></span>I am a sentence.<span class="tag"></<span class="name">span</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">ReactDOM</span>.<span class="title function_">render</span>(</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">React.StrictMode</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">App</span> <span class="attr">color</span>=<span class="string">"blue"</span> <span class="attr">size</span>=<span class="string">"25"</span>/></span> <span class="comment"><!-- props being sent to the component --></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">React.StrictMode</span>></span></span>,</span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'root'</span>)</span><br><span class="line">);</span><br></pre></td></tr></tbody></table></figure>
<p>事件处理程序(event handler)可以通过属性来设置,其中 <code>onClick</code> 处理程序在功能组件中使用的最多:</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">ReactDOM</span> <span class="keyword">from</span> <span class="string">'react-dom'</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">App</span> <span class="keyword">from</span> <span class="string">'./App'</span>;</span><br><span class="line"></span><br><span class="line"><span class="title class_">ReactDOM</span>.<span class="title function_">render</span>(</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">React.StrictMode</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">App</span> <span class="attr">color</span>=<span class="string">"blue"</span> <span class="attr">size</span>=<span class="string">"25"</span> <span class="attr">clickEvent</span>=<span class="string">{</span> <!<span class="attr">--</span> <span class="attr">setting</span> <span class="attr">an</span> <span class="attr">event</span> <span class="attr">handler</span> <span class="attr">method</span> <span class="attr">as</span> <span class="attr">a</span> <span class="attr">property</span> <span class="attr">--</span>></span></span></span><br><span class="line"><span class="language-xml"> () => { alert("You clicked me!") }</span></span><br><span class="line"><span class="language-xml"> }/></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">React.StrictMode</span>></span></span>,</span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'root'</span>)</span><br><span class="line">);</span><br></pre></td></tr></tbody></table></figure>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">App</span>(<span class="params">props</span>) {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{props.clickEvent}</span>></span>Click Me!<span class="tag"></<span class="name">button</span>></span> <span class="comment"><!-- setting an event handler from props --></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>类组件要比函数式组件更复杂,它们可以将数据传递给其他类组件、可以被 JavaScript ES6 的类创建、可以使用状态、属性和生命周期方法等 React 功能。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Democomponent</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">h1</span>></span>Welcome Message!<span class="tag"></<span class="name">h1</span>></span></span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>由于其多功能性,类组件要比函数式组件更受青睐。由于它们继承了 <code>React.Component</code>,因此必须要覆盖 <code>render()</code> 方法。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// import the React module from the react package</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// create the App class that extends React.Component</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params">props</span>) {</span><br><span class="line"> <span class="variable language_">super</span>(props)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// override the render method</span></span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{this.props.clickEvent}</span>></span>Click Me!<span class="tag"></<span class="name">button</span>></span></span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
<p><code>props</code> 在类组件外部设置,而状态要在类组件内部设置:</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">Reach</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params">props</span>) {</span><br><span class="line"> <span class="variable language_">super</span>(props)</span><br><span class="line"> }</span><br><span class="line"> state = {<span class="attr">counter</span>: <span class="string">"0"</span>}; <span class="comment">// define the state counter of the component App</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">// a function to increment the counter every time a button is clicked</span></span><br><span class="line"> incrementCounter = <span class="function">() =></span> {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">counter</span>: <span class="built_in">parseInt</span>(<span class="variable language_">this</span>.<span class="property">state</span>.<span class="property">counter</span>) + <span class="number">1</span>});</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// override the render method</span></span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{this.incrementCounter}</span>></span>Click Me!<span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">br</span>/></span></span></span><br><span class="line"><span class="language-xml"> {this.state.counter}</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>纯组件(pure component)优于函数式组件,主要用于提供优化。它们是编写起来最简单最快的组件,不依赖于其作用域之外的任何变量状态,可以用来替代简单的函数式组件。</p>
</li>
<li>
<p>高阶组件(higher-order component)是 React 中重用组件逻辑的高级技术。API 不提供高阶组件。它们返回组件的函数,用于与其他组件共享逻辑。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// import React and React Native's Text Core Component</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">Text</span> } <span class="keyword">from</span> <span class="string">'react-native'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// define a component as a function</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">Helloworld</span> = (<span class="params"></span>) => {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">Text</span>></span>Hello, World!<span class="tag"></<span class="name">Text</span>></span></span></span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// export your function component</span></span><br><span class="line"><span class="comment">// the function can then be imported in any application</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">Helloworld</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
</ol>
<h1 id="2-react组件"><a class="markdownIt-Anchor" href="#2-react组件"></a> 2. React 组件</h1>
<h2 id="21-状态"><a class="markdownIt-Anchor" href="#21-状态"></a> 2.1. 状态</h2>
<p>状态允许你在一个应用程序中修改数据。它被定义为一个对象,使用键值对来存储数据,并帮助你跟踪应用程序中不同类型的数据。</p>
<p>React 组件有一个内置的状态对象,可以在状态对象中存储属于组件的属性值。当状态对象发生变化时,组件会重新渲染。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// component</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">TestComponent</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.component</span> {</span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">state</span> = {</span><br><span class="line"> <span class="attr">id</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="attr">name</span>: <span class="string">"John"</span>,</span><br><span class="line"> <span class="attr">age</span>: <span class="number">28</span></span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">p</span>></span>{ this.state.name }<span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">p</span>></span>{ this.state.age }<span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>本代码示例展示出了如何创建一个测试组件,该组件包含 <code>id</code>、<code>name</code> 和 <code>age</code> 三个状态属性</li>
<li>组件的 <code>render()</code> 方法返回了状态属性的值</li>
<li>包含属性的状态将根据组件的要求进行更改</li>
</ul>
<p>React 状态的类型:</p>
<ol>
<li>共享状态(shared state):由多个组件共享,比较复杂。例如订单应用程序中的所有订单列表</li>
<li>本地状态(local state):存在于单个组件中,不用于其他组件。例如隐藏和显示信息</li>
</ol>
<h2 id="22-属性"><a class="markdownIt-Anchor" href="#22-属性"></a> 2.2. 属性</h2>
<p>属性用于在 React 组件之间传递数据。工作方式与 HTML 属性类似,它们存储标签的属性值。</p>
<blockquote>
<p>React 组件之间的数据流是从父组件到子组件的单向数据流。</p>
</blockquote>
<p>属性可以像函数参数一样被传递,但它们是只读的,不能在组件内部更改。属性允许子组件访问父组件中被定义的方法(状态则是由父组件管理,而子组件没有自己的状态),大部分组件将根据接收到的属性来显示信息,并保持无状态。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// component</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">TestComponent</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.component</span> {</span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span>Hi { this.props.name }<span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// passing the props as examples to the text component</span></span><br><span class="line"><<span class="title class_">TestComponent</span> name=<span class="string">"John"</span> /></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">TestComponent</span> <span class="attr">name</span>=<span class="string">"Jill"</span> /></span></span></span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>该代码示例创建了一个类 <code>TestComponent</code>,该类扩展了 React 组件</li>
</ul>
<h2 id="23-组件阶段"><a class="markdownIt-Anchor" href="#23-组件阶段"></a> 2.3. 组件阶段</h2>
<p>每个 React 组件在其生命周期中都有三个阶段:</p>
<ol>
<li>
<p>挂载阶段(mounting phase):组件被创建并插入 DOM 中。当组件被创建时,会有四个方法被依次调用:</p>
<ol>
<li><code>constructor()</code>:用于初始化组件的状态和属性</li>
<li><code>getDerivedStateFromProps()</code>:用于更新组件的状态</li>
<li><code>render()</code>:用于渲染组件;必须且只能返回一个 DOM 元素</li>
<li><code>componentDidMount()</code>:用于在组件被插入 DOM 后执行一些操作</li>
</ol>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> <span class="comment">// when the component App is created, the constructor is invoked</span></span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params">props</span>) {</span><br><span class="line"> <span class="variable language_">super</span>(props)</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Inside the constructor"</span>)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// the componentDidMount method is invoked</span></span><br><span class="line"> componentDidMount = <span class="function">() =></span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Inside component did mount"</span>)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// the render method is invoked</span></span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Inside render method"</span>)</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> The component is rendered</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>更新阶段(updating phase):组件的状态或属性发生变化时,会触发更新阶段。当组件更新时,会有五个方法被依次调用:</p>
<ol>
<li><code>getDerivedStateFromProps()</code>:用于更新组件的状态</li>
<li><code>shouldComponentUpdate()</code>:每当状态发生变化时被调用;默认返回 <code>true</code>;应当仅在不想渲染状态的变化时返回 <code>false</code></li>
<li><code>render()</code>:用于渲染组件;必须且只能返回一个 DOM 元素</li>
<li><code>getSnapshotBeforeUpdate()</code>:用于在 DOM 更新前获取 DOM 状态</li>
<li><code>componentDidUpdate()</code>:用于在 DOM 更新后执行一些操作</li>
</ol>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> state = {<span class="attr">counter</span>: <span class="string">"0"</span>};</span><br><span class="line"> </span><br><span class="line"> incrementCounter = <span class="function">() =></span> <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">counter</span>: <span class="built_in">parseInt</span>(<span class="variable language_">this</span>.<span class="property">state</span>.<span class="property">counter</span>) + <span class="number">1</span>});</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// returns true by default</span></span><br><span class="line"> <span class="comment">// its behavior is rarely changed</span></span><br><span class="line"> <span class="title function_">shouldComponentUpdate</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside shouldComponentUpdate'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="title function_">getSnapshotBeforeUpdate</span>(<span class="params">prevProps, prevState</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside getSnapshotBeforeUpdate'</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Prev counter is '</span> + prevState.<span class="property">counter</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'New counter is '</span> + <span class="variable language_">this</span>.<span class="property">state</span>.<span class="property">counter</span>);</span><br><span class="line"> <span class="keyword">return</span> prevState;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="title function_">componentDidUpdate</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside componentDidUpdate'</span>)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// logs on to the console and then renders the component</span></span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside render'</span>)</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="comment"><!-- With the onClick of the button, incrementCounter is invoked, increasing the counter state by 1 --></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{this.incrementCounter}</span>></span>Click Me!<span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"><span class="language-xml"> {this.state.counter}</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>卸载阶段(unmounting phase):组件从 DOM 中移除时,会触发卸载阶段。当组件被卸载时,会有一个方法被调用:</p>
<ol>
<li><code>componentWillUnmount()</code>:用于在组件被卸载前执行一些操作</li>
</ol>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">AppInner</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> <span class="title function_">componentWillUnmount</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'This component will unmount'</span>)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span>Inner component<span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> state = {<span class="attr">innerComponent</span>:<span class="language-xml"><span class="tag"><<span class="name">AppInner</span>/></span></span>}</span><br><span class="line"> </span><br><span class="line"> <span class="title function_">componentDidMount</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="built_in">setTimeout</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">innerComponent</span>: <span class="language-xml"><span class="tag"><<span class="name">div</span>></span>unmounted<span class="tag"></<span class="name">div</span>></span></span>}) </span><br><span class="line"> }, <span class="number">5000</span>)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside render'</span>)</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> {this.state.innerComponent}</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
</ol>
<h2 id="24-组件之间的数据传递"><a class="markdownIt-Anchor" href="#24-组件之间的数据传递"></a> 2.4. 组件之间的数据传递</h2>
<p>React 组件之间的数据传递可以有:</p>
<ol>
<li>使用属性的「父到子」数据传递</li>
<li>使用回调函数的「子到父」数据传递</li>
<li>使用 Redux 的「兄弟」数据传递(此处不做讨论)</li>
</ol>
<p>父到子:</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> state = {<span class="attr">childColor</span>: <span class="string">"green"</span>, <span class="attr">name</span>: <span class="string">"John"</span>}</span><br><span class="line"> </span><br><span class="line"> changeColor = <span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">const</span> newcolor = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'colorbox'</span>).<span class="property">value</span>;</span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">childColor</span>: newcolor})</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> changeName = <span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">const</span> newname = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'namebox'</span>).<span class="property">value</span>;</span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">name</span>: newname})</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside render'</span>)</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> Color <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"Text"</span> <span class="attr">onChange</span>=<span class="string">{this.changeColor}</span> <span class="attr">id</span>=<span class="string">"colorbox"</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">br</span>/></span></span></span><br><span class="line"><span class="language-xml"> Name <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"Text"</span> <span class="attr">onChange</span>=<span class="string">{this.changeName}</span> <span class="attr">id</span>=<span class="string">"namebox"</span> /></span></span></span><br><span class="line"><span class="language-xml"> </span></span><br><span class="line"><span class="language-xml"> <span class="comment"><!-- App sets the property color and name for AppInner --></span></span></span><br><span class="line"><span class="language-xml"> <span class="comment"><!-- The data is passed to the child every time a new value is entered in the input boxes in the parent --></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">AppInner</span> <span class="attr">color</span>=<span class="string">{this.state.childColor}</span> <span class="attr">name</span>=<span class="string">{this.state.name}</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">AppInner</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params">props</span>) {</span><br><span class="line"> <span class="variable language_">super</span>(props)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">const</span> txtStyle = {<span class="attr">color</span>: <span class="variable language_">this</span>.<span class="property">props</span>.<span class="property">color</span>}</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">span</span> <span class="attr">style</span>=<span class="string">{txtStyle}</span>></span>{this.props.name}<span class="tag"></<span class="name">span</span>></span></span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>其中,<code>App</code> 组件是 <code>AppInner</code> 组件的父组件</li>
</ul>
<p>子到父:</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> state = {<span class="attr">message</span>: <span class="string">""</span>}</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// Func1 is a parent component function which takes a string argument</span></span><br><span class="line"> func1 = <span class="function">(<span class="params">childData</span>) =></span> {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">message</span>: childData})</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="comment"><!-- Pass the callback func1 as a property to the child --></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">AppInner</span> <span class="attr">parentCallback</span> = <span class="string">{this.func1}</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">p</span>></span>{this.state.message}<span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">AppInner</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> sendData = <span class="function">() =></span> {</span><br><span class="line"> <span class="built_in">setInterval</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">const</span> currTime = <span class="title class_">Date</span>();</span><br><span class="line"> <span class="comment">// the parent class method which sets the state of the parent component</span></span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">props</span>.<span class="title function_">parentCallback</span>(currTime);</span><br><span class="line"> }, <span class="number">1000</span>);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// invoke the sendData method</span></span><br><span class="line"> <span class="title function_">componentDidMount</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">sendData</span>();</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span><span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<h2 id="25-组件的生命周期"><a class="markdownIt-Anchor" href="#25-组件的生命周期"></a> 2.5. 组件的生命周期</h2>
<p>组件的生命周期代表了组件从创建到销毁的整个过程。React 组件的生命周期包含四个阶段,每个阶段都有不同的方法:</p>
<ol>
<li>初始化(initialization):组件以给定的属性和默认状态被创建</li>
<li>挂载(mounting):渲染由 <code>render()</code> 方法返回的 JSX</li>
<li>更新(updating):当组件的状态或属性发生变化时,会触发更新阶段</li>
<li>卸载(unmounting):组件从 DOM 中移除</li>
</ol>
<h4 id="251-挂载阶段"><a class="markdownIt-Anchor" href="#251-挂载阶段"></a> 2.5.1. 挂载阶段</h4>
<p>挂载阶段中,组件被添加到 DOM,并在组件加载前和加载后调用两个预定义方法:</p>
<ol>
<li><code>componentWillMount()</code></li>
<li><code>componentDidMount()</code></li>
</ol>
<h4 id="252-更新阶段"><a class="markdownIt-Anchor" href="#252-更新阶段"></a> 2.5.2. 更新阶段</h4>
<p>组件的状态或属性发生变化时,会触发更新阶段。变化可以在组件内发生,也可以通过后台发生,这些变化都会触发 <code>render()</code> 方法的调用。</p>
<ol>
<li><code>getDerivedStateFromProps()</code></li>
<li><code>shouldComponentUpdate()</code></li>
<li><code>render()</code></li>
<li><code>getSnapshotBeforeUpdate()</code></li>
<li><code>componentDidUpdate()</code></li>
</ol>
<h4 id="253-卸载阶段"><a class="markdownIt-Anchor" href="#253-卸载阶段"></a> 2.5.3. 卸载阶段</h4>
<p>组件从 DOM 中移除时,会触发卸载阶段。在卸载阶段,只有一个方法被调用:</p>
<ol>
<li><code>componentWillUnmount()</code></li>
</ol>
<h2 id="26-外部服务"><a class="markdownIt-Anchor" href="#26-外部服务"></a> 2.6. 外部服务</h2>
<p>路由器(router)可以连接到外部服务以执行多种操作,例如:</p>
<ol>
<li>
<p><code>GET</code>:从服务器获取数据</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> state = {</span><br><span class="line"> <span class="attr">user</span>: <span class="string">"None Logged In"</span></span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// connect to a server through an axios request</span></span><br><span class="line"> <span class="title function_">componentDidMount</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">const</span> req = axios.<span class="title function_">get</span>(<span class="string">"<external server>"</span>);</span><br><span class="line"> req.<span class="title function_">then</span>(<span class="function"><span class="params">resp</span> =></span> {</span><br><span class="line"> <span class="comment">// then the promise is fulfilled, you parse the response and extract the data from it to change user to have the same name as its value</span></span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">user</span>: resp.<span class="property">data</span>.<span class="property">name</span>});</span><br><span class="line"> })</span><br><span class="line"> .<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =></span> {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">user</span>: <span class="string">"Invalid user"</span>});</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> Current user - {this.state.user}</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p><code>POST</code>:将数据发送到服务器</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">"express"</span>);</span><br><span class="line"><span class="keyword">const</span> app = <span class="keyword">new</span> <span class="title function_">express</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">// this server uses the CORS middleware to allow cross-origin requests to the server</span></span><br><span class="line"><span class="keyword">const</span> cors_app = <span class="built_in">require</span>(<span class="string">"cors"</span>);</span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">cors_app</span>());</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> usercollection = [];</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">"/user"</span>, <span class="function">(<span class="params">req, res</span>) =></span> {</span><br><span class="line"> <span class="keyword">let</span> newuser = {<span class="string">"name"</span>: req.<span class="property">query</span>.<span class="property">name</span>, <span class="string">"gender"</span>: req.<span class="property">query</span>.<span class="property">gender</span>}</span><br><span class="line"> usercollection.<span class="title function_">push</span>(newuser);</span><br><span class="line"> <span class="keyword">return</span> res.<span class="title function_">send</span>(<span class="string">"User successfully added"</span>);</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">"/user"</span>, <span class="function">(<span class="params">req, res</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> res.<span class="title function_">send</span>(usercollection);</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">3333</span>, <span class="function">() =></span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Listening at http://localhost:3333"</span>)</span><br><span class="line">})</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>Express 服务器接收端点 <code>/user</code> 的 <code>POST</code> 请求,并将数据存储在 <code>usercollection</code> 数组中</li>
</ul>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> state = {<span class="attr">completionstatus</span>: <span class="string">""</span>}</span><br><span class="line"> </span><br><span class="line"> postDataToServer = <span class="function">() =></span> {</span><br><span class="line"> axios.<span class="title function_">post</span>(<span class="string">"http://localhost:3333/user?name="</span> +</span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"name"</span>).<span class="property">value</span> +</span><br><span class="line"> <span class="string">"&gender="</span> + <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"gender"</span>).<span class="property">value</span></span><br><span class="line"> )</span><br><span class="line"> .<span class="title function_">then</span>(<span class="function"><span class="params">response</span> =></span> {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">completionstatus</span>: response.<span class="property">data</span>})</span><br><span class="line"> }).<span class="title function_">catch</span>(<span class="function">(<span class="params">err</span>) =></span> {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">completionstatus</span>: <span class="string">"Operation failure"</span>})</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> Enter the name <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"name"</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">br</span> /></span></span></span><br><span class="line"><span class="language-xml"> Enter the gender <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"gender"</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">br</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{this.postDataToServer}</span>></span>Post Data<span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">span</span>></span>{this.state.completionstatus}<span class="tag"></<span class="name">span</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p><code>UPDATE</code>:修改数据</p>
</li>
<li>
<p><code>DELETE</code>:删除数据</p>
</li>
</ol>
<p>大多数对外部服务器的请求都是阻塞性的。要异步调用,可以使用 Promise。</p>
<h2 id="27-测试"><a class="markdownIt-Anchor" href="#27-测试"></a> 2.7. 测试</h2>
<p>测试可以是一套由代码组成的,以验证应用程序的无差错执行。</p>
<p>测试 React 组件有多个好处:验证代码运行无误;通过复制最终用户的行为来测试组件;通过测试组件的不同状态来测试组件;防止先前已修复的错误再次出现。</p>
<p>测试有着两种类型:</p>
<ol>
<li>在简单的测试环境中渲染组件树并验证其输出</li>
<li>在真实的浏览器环境中运行应用程序,进行端到端的测试</li>
</ol>
<h4 id="271-react组件测试的阶段"><a class="markdownIt-Anchor" href="#271-react组件测试的阶段"></a> 2.7.1. React 组件测试的阶段</h4>
<ol>
<li>安排(arrange):组件需要将其 DOM 渲染到用户界面</li>
<li>操作(act):注册任何可能以编程方法触发的用户行为</li>
<li>断言(assert):验证组件的输出是否与预期的输出相匹配</li>
</ol>
<h4 id="272-测试工具"><a class="markdownIt-Anchor" href="#272-测试工具"></a> 2.7.2. 测试工具</h4>
<p>速度 vs 环境:</p>
<ul>
<li>有些工具能在做出修改和看到结果之间提供非常快的回馈,但无法精确地模拟浏览器行为</li>
<li>有些工具可能会使用真实的浏览器环境,但会降低迭代速度,在持续集成环境中使用时可能会导致不稳定</li>
</ul>
<p>测试工具有:</p>
<ul>
<li>Mocha</li>
<li>Chai:断言库</li>
<li>Sinon</li>
<li>Enzyme:渲染组件</li>
<li>Jest:测试 React 组件,并拥有着 Mocha、Chai、Sinon 以及其他工具的能力</li>
<li>React Testing Library:测试 React 组件</li>
</ul>
<h1 id="3-react进阶"><a class="markdownIt-Anchor" href="#3-react进阶"></a> 3. React 进阶</h1>
<h2 id="31-hooks"><a class="markdownIt-Anchor" href="#31-hooks"></a> 3.1. Hooks</h2>
<p>Hooks 是在用户界面中封装有状态的行为的更简单的方法,它们允许函数式组件访问状态和其他 React 功能。Hooks 是常规的 JavaScript 函数,提供使用上下文或状态等功能的方法,且无需编写类,帮助你使代码更简洁。</p>
<blockquote>
<p>类组件有时会带来一些问题,例如封装复杂、组件大小难以管理以及类混淆等。</p>
</blockquote>
<p>标准的 Hooks:</p>
<ul>
<li><code>useState</code>:为函数式组件添加状态</li>
<li><code>useEffect</code>:管理副作用(side effects)</li>
<li><code>useContext</code>:管理上下文</li>
<li><code>useReducer</code>:管理 Redux 的状态变化</li>
</ul>
<p>自定义 Hooks 允许你为应用程序添加特殊功能。它们可以由一个或多个 Hooks 组成、可以被重复使用、分解为更小的 Hooks。自定义 Hooks 需要以 <code>use</code> 开头。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span>, { useState } <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">CntApp</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="comment">// declare a new state variable "count"</span></span><br><span class="line"> <span class="comment">// useState is the hook which needs to call inside a function component to add some local state to it</span></span><br><span class="line"> <span class="keyword">const</span> [count, setCount] = <span class="title function_">useState</span>(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">p</span>></span>You clicked {count} many times<span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{()</span> =></span> setCount(count + 1)}></span></span><br><span class="line"><span class="language-xml"> Click me</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">CntApp</span>;</span><br></pre></td></tr></tbody></table></figure>
<h2 id="32-表单"><a class="markdownIt-Anchor" href="#32-表单"></a> 3.2. 表单</h2>
<p>大多数 React 表单都是单页面应用程序(SPA)或者加载单个页面的网络应用程序。表单使用组件处理数据、使用事件处理程序控制变量的变化和状态的更新。</p>
<p>表单标签有:</p>
<ul>
<li><code><input></code></li>
<li><code><textarea></code></li>
<li><code><select></code></li>
</ul>
<p>在 HTML,状态由表单元素管理;在 React,组件的状态管理着表单元素。</p>
<h4 id="321-输入类型"><a class="markdownIt-Anchor" href="#321-输入类型"></a> 3.2.1. 输入类型</h4>
<table>
<thead>
<tr>
<th>非受控输入</th>
<th>受控输入</th>
</tr>
</thead>
<tbody>
<tr>
<td>允许浏览器处理大部分表单元素,并通过 React 的变化事件收集数据</td>
<td>使用 React 直接设置和更新输入值,从而完全控制元素</td>
</tr>
<tr>
<td>在输入的 DOM 节点中管理自己的状态</td>
<td>函数管理数据的传递</td>
</tr>
<tr>
<td>元素会在输入值发生变化的时候更新</td>
<td>更好地控制表单元素和数据</td>
</tr>
<tr>
<td><code>ref</code> 函数用于从 DOM 中获取表单值</td>
<td>属性获取当前值并通知更改</td>
</tr>
<tr>
<td></td>
<td>父组件控制更改</td>
</tr>
</tbody>
</table>
<p>表单示例:</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span>, { <span class="title class_">Component</span> } <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">App</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="comment">// to track the state of the email address, this example uses a hook</span></span><br><span class="line"> <span class="keyword">const</span> [email, setEmail] = <span class="title class_">React</span>.<span class="title function_">useState</span>(<span class="string">""</span>);</span><br><span class="line"> <span class="keyword">const</span> [password, setPassword] = <span class="title class_">React</span>.<span class="title function_">useState</span>(<span class="string">""</span>);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">const</span> <span class="title function_">handleSubmit</span> = (<span class="params">event</span>) => {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Email: ${email}\nPassword: ${password}"</span>);</span><br><span class="line"> event.<span class="title function_">preventDefault</span>();</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">form</span> <span class="attr">onSubmit</span>=<span class="string">{handleSubmit}</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">h1</span>></span>Registration<span class="tag"></<span class="name">h1</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">label</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="comment"><!-- to ensure that the email remains updated when the use interacts with form, you must add as input, value, and onChange attributes to the email address --></span></span></span><br><span class="line"><span class="language-xml"> Email: <span class="tag"><<span class="name">input</span> <span class="attr">name</span>=<span class="string">"email"</span> <span class="attr">type</span>=<span class="string">"email"</span> <span class="attr">value</span>=<span class="string">{email}</span> <span class="attr">onChange</span>=<span class="string">{e</span> =></span> setEmail(e.target.value)} required /></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">label</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">label</span>></span></span></span><br><span class="line"><span class="language-xml"> Password: <span class="tag"><<span class="name">input</span> <span class="attr">name</span>=<span class="string">"password"</span> <span class="attr">type</span>=<span class="string">"password"</span> <span class="attr">value</span>=<span class="string">{password}</span> <span class="attr">onChange</span>=<span class="string">{e</span> =></span> setPassword(e.target.value)} required /></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">label</span>></span></span></span><br><span class="line"><span class="language-xml"> </span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">button</span>></span>Submit<span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">form</span>></span></span></span><br><span class="line"> );</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<blockquote>
<p>React Hook Form 是一个创建表单的实用软件包,它可以帮助你创建可重用的表单组件。</p>
</blockquote>
<h2 id="33-redux"><a class="markdownIt-Anchor" href="#33-redux"></a> 3.3. Redux</h2>
<p>Redux 是一个状态管理库,它遵循一种称为 Flux 架构的模式,通常在组件数量较多的时候实用。</p>
<p>Redux 提供了一个集中的状态管理系统,它将应用程序的所有状态存储在一个单一的对象中,称为存储(store)。存储是一个 JavaScript 对象,它包含了应用程序的所有状态。</p>
<p>Redux 的工作流程:当用户与应用程序的某个组件交互时,<code>Action</code> 会更新整个应用程序的状态,这反过来又会触发组件的重新渲染,从而更新该组件的属性,这些属性会将结果反馈给用户。</p>
<h4 id="331-概念"><a class="markdownIt-Anchor" href="#331-概念"></a> 3.3.1. 概念</h4>
<ol>
<li><code>Action</code>:【你的应用程序能做什么】。它是一个由选择单选按钮、复选框或点击按钮触发的事件 / JSON 对象;它包含着需要对状态进行更改的信息,并由被称为操作创建器(action creator)的函数创建。<code>Action</code> 由应用程序的各个部分派发,并由存储空间接收</li>
<li><code>Store</code>:应用程序状态的唯一位置和权威来源。它是一个包含着状态、函数和其他对象的对象,可以调度和接收操作。<code>Store</code> 的更新能够被订阅</li>
<li><code>Reducers</code>:返回全新的状态的函数。它们从 <code>Store</code> 接收 <code>Action</code>,并对状态进行适当更改。作为事件监听器,<code>Reducer</code> 会读取 <code>Action</code> 的有效载荷(payload)并更新 <code>Store</code>。
<ul>
<li><code>Reducer</code> 接收两个参数:先前的应用程序状态和 <code>Action</code></li>
</ul>
</li>
</ol>
<h4 id="332-中间件"><a class="markdownIt-Anchor" href="#332-中间件"></a> 3.3.2 中间件</h4>
<p>中间件(middleware)是一个函数,它可以访问 <code>Action</code> 和 <code>Store</code>,并且可以在 <code>Action</code> 到达 <code>Reducer</code> 之前执行某些操作。它可以用于日志记录、分析、异步请求等。</p>
<ol>
<li>Thunk 中间件:允许在操作创建器中传递函数以创建 <code>async</code> Redux、允许编写操作创建器、允许延迟调度操作、允许调度多个操作。优势是 Thunk 中间件可以无需大量模板代码即可实现异步操作、学习难度小、易于使用;缺点是不能直接对操作做出响应、难以处理可能出现的并发问题、是命令式的、不太容易测试和扩展</li>
<li>Saga 中间件:使用称为生成器(generator)的 ES6 功能来实现异步操作、允许以纯函数的形式表达复杂的逻辑、易于测试、允许分离关注点、易于扩展具有副作用的复杂操作、易于通过 <code>try/catch</code> 处理错误;缺点是不适合简单的应用程序、需要更多的模板代码、需要具备生成器的知识</li>
<li>基于 Promise 的中间件</li>
</ol>
<h4 id="333-数据流"><a class="markdownIt-Anchor" href="#333-数据流"></a> 3.3.3. 数据流</h4>
<p>React-Redux 应用程序的数据流是单向的。它只朝一个方向流动。</p>
<ol>
<li>操作创建器(action creator)朝根归纳器(root reducer)流动</li>
<li>根归纳器处理 <code>Action</code> 并返回新的状态到储存空间(store)</li>
<li>存储空间更新用户界面(UI)</li>
<li>用户界面调用操作创建器</li>
</ol>
<p>为什么要选择单向数据流:双向数据绑定会影响浏览器性能,而且很难跟踪数据流,因此 Redux 的单向数据流解决了这个问题。</p>
</body></html></div></article></div></main><footer><div class="paginator"><a class="prev" href="fed2.html">上一篇</a><a class="next" href="d62.html">下一篇</a></div><!-- Webmention 显示区域--><div class="webmention-section webmention-empty" data-page-url="posts/d011.html" data-full-url="https://cytrogen.icu/posts/d011.html" data-mode="static">
<h3 class="webmention-title">Webmentions (<span class="webmention-count">0</span>)</h3>
<div class="webmention-list"></div>
<span>暂无 Webmentions</span>
</div><div class="copyright"><p class="footer-links"><a href="../friends/index.html">友链</a><span class="footer-separator"> ·</span><a href="../links/index.html">邻邦</a><span class="footer-separator"> ·</span><a href="../contact/index.html">联络</a><span class="footer-separator"> ·</span><a href="../colophon/index.html">营造记</a><span class="footer-separator"> ·</span><a href="../atom.xml">RSS订阅</a></p><p>© 2025 - 2026 <a href="https://cytrogen.icu">Cytrogen</a>, powered by <a href="https://hexo.io/" target="_blank">Hexo</a> and <a href="https://github.com/cytrogen/hexo-theme-ares" target="_blank">hexo-theme-ares</a>.</p><p><a href="https://blogscn.fun" target="_blank" rel="noopener">BLOGS·CN</a></p></div></footer></div></div><a class="back-to-top" href="#top" aria-label="返回顶部"><svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M3.293 9.707a1 1 0 010-1.414L9.586 2a2 2 0 012.828 0l6.293 6.293a1 1 0 01-1.414 1.414L11 3.414V17a1 1 0 11-2 0V3.414L2.707 9.707a1 1 0 01-1.414 0z"></path></svg></a><script>document.addEventListener('DOMContentLoaded', function() {
const codeBlocks = document.querySelectorAll('figure.highlight');
codeBlocks.forEach(block => {
let caption = block.querySelector('figcaption');
if (!caption) {
caption = document.createElement('figcaption');
block.insertBefore(caption, block.firstChild);
}
const info = document.createElement('div');
info.className = 'info';
const filename = caption.querySelector('span');
if (filename) {
filename.className = 'filename';
info.appendChild(filename);
}
const lang = block.className.split(' ')[1];
if (lang) {
const langSpan = document.createElement('span');
langSpan.className = 'lang-name';
langSpan.textContent = lang;
info.appendChild(langSpan);
}
const sourceLink = caption.querySelector('a');
if (sourceLink) {
sourceLink.className = 'source-link';
info.appendChild(sourceLink);
}
const actions = document.createElement('div');
actions.className = 'actions';
const codeHeight = block.scrollHeight;
const threshold = 300;
if (codeHeight > threshold) {
block.classList.add('folded');
const toggleBtn = document.createElement('button');
toggleBtn.textContent = '展开';
toggleBtn.addEventListener('click', () => {
block.classList.toggle('folded');
toggleBtn.textContent = block.classList.contains('folded') ? '展开' : '折叠';
});
actions.appendChild(toggleBtn);
}
const copyBtn = document.createElement('button');
copyBtn.textContent = '复制';
copyBtn.addEventListener('click', async () => {
const codeLines = block.querySelectorAll('.code .line');
const code = Array.from(codeLines)
.map(line => line.textContent)
.join('\n')
.replace(/\n\n/g, '\n');
try {
await navigator.clipboard.writeText(code);
copyBtn.textContent = '已复制';
copyBtn.classList.add('copied');
setTimeout(() => {
copyBtn.textContent = '复制';
copyBtn.classList.remove('copied');
}, 3000);
} catch (err) {
console.error('复制失败:', err);
copyBtn.textContent = '复制失败';
setTimeout(() => {
copyBtn.textContent = '复制';
}, 3000);
}
});
actions.appendChild(copyBtn);
caption.innerHTML = '';
caption.appendChild(info);
caption.appendChild(actions);
const markedLines = block.getAttribute('data-marked-lines');
if (markedLines) {
const lines = markedLines.split(',');
lines.forEach(range => {
if (range.includes('-')) {
const [start, end] = range.split('-').map(Number);
for (let i = start; i <= end; i++) {
const line = block.querySelector(`.line-${i}`);
if (line) line.classList.add('marked');
}
} else {
const line = block.querySelector(`.line-${range}`);
if (line) line.classList.add('marked');
}
});
}
});
});</script><script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" id="MathJax-script"></script><script>(function() {
document.addEventListener('DOMContentLoaded', function() {
const themeToggle = document.querySelector('.theme-toggle');
if (!themeToggle) return;
const getCurrentTheme = () => {
return document.documentElement.getAttribute('data-theme') || 'light';
};
const updateUI = (theme) => {
const isDark = theme === 'dark';
themeToggle.setAttribute('aria-pressed', isDark.toString());
};
const setTheme = (theme) => {
document.documentElement.setAttribute('data-theme', theme);
document.documentElement.style.colorScheme = theme;
const pageWrapper = document.getElementById('page-wrapper');
if (pageWrapper) {
pageWrapper.setAttribute('data-theme', theme);
}
// Find and remove the temporary anti-flicker style tag if it exists.
// This ensures the main stylesheet takes full control after the initial load.
const antiFlickerStyle = document.getElementById('anti-flicker-style');
if (antiFlickerStyle) {
antiFlickerStyle.remove();
}
localStorage.setItem('theme', theme);
updateUI(theme);
};
const toggleTheme = () => {
const current = getCurrentTheme();
const newTheme = current === 'light' ? 'dark' : 'light';
setTheme(newTheme);
};
updateUI(getCurrentTheme());
themeToggle.addEventListener('click', toggleTheme);
if (window.matchMedia) {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addEventListener('change', function(e) {
if (!localStorage.getItem('theme')) {
const theme = e.matches ? 'dark' : 'light';
setTheme(theme);
}
});
}
});
})();
</script><script src="../js/details-toggle.js" defer></script><script>(function() {
document.addEventListener('DOMContentLoaded', function() {
const backToTopBtn = document.querySelector('.back-to-top');
if (!backToTopBtn) return;
const toggleButtonVisibility = () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const shouldShow = scrollTop > 200;
if (shouldShow) {
backToTopBtn.classList.add('is-visible');
} else {
backToTopBtn.classList.remove('is-visible');
}
};
let ticking = false;
const handleScroll = () => {
if (!ticking) {
requestAnimationFrame(() => {
toggleButtonVisibility();
ticking = false;
});
ticking = true;
}
};
const scrollToTop = (event) => {
event.preventDefault();
window.scrollTo({
top: 0,
behavior: 'smooth'
});
};
window.addEventListener('scroll', handleScroll);
backToTopBtn.addEventListener('click', scrollToTop);
toggleButtonVisibility();
});
})();</script></body></html>