从 Create React App(CRA)迁移
Astro 的 React 集成 支持在 Astro 组件中使用 React 组件,甚至包括像 Create React App (CRA) 这样的整个 React 应用程序!
---// 导入你的根应用组件import App from '../cra-project/App.jsx';---<!-- 使用客户端指令加载你的应用 --><App client:load />
当你在已安装 React 集成的 Astro 项目中直接添加应用时,许多应用程序将会作为完整的 React 应用程序运行。这是一个快速启动项目并在迁移到 Astro 过程中保持应用功能的绝佳方式。
随着时间的推移,你可以逐步将结构转换为由 .astro
和 .jsx
组件组合而成的形式。届时,你可能会发现你需要的 React 组件比你想象中的要少!
以下是一些关键概念和迁移策略帮助你入门,也可以继续阅读我们的文档和参与我们的 Discord 社区 以获取更多帮助!
CRA 和 Astro 的关键相似之处
段落标题 CRA 和 Astro 的关键相似之处-
.astro
文件的语法与 JSX 类似。编写 Astro 应该会让你感到熟悉。 -
Astro 使用基于文件的路由,并允许通过特殊的文件命名来创建动态路由。
-
Astro 是基于组件的,你的标记结构在迁移前后将类似。
-
Astro 提供了 React、Preact 和 Solid 的官方集成,因此你可以使用现有的 JSX 组件。请注意,这意味着在 Astro 中,这些文件的扩展名必须为
.jsx
或.tsx
。 -
Astro 支持 安装 NPM 包,包括 React 库。许多现有的依赖项在 Astro 中可以正常工作。
CRA 和 Astro 的关键差异
段落标题 CRA 和 Astro 的关键差异在用 Astro 重新构建 CRA 站点时,你会注意到一些重要的差异:
-
CRA 是一个使用
index.js
作为项目根目录的单页面应用程序。Astro 是一个多页面站点,其中index.astro
是你的首页。 -
.astro
组件 不是作为返回页面模板的导出函数而被构建。相反,你需要将代码分割到一个用于 JavaScript 的“代码围栏”和一个专门用于生成的 HTML 的“body”中。 -
内容驱动:Astro 的设计目标是展示你的内容,并允许你在需要时选择性地启用交互。如果现有的 CRA 应用用于构建高级的客户端交互,那么可能需要使用高级的 Astro 技术来让
.astro
组件来完成更具挑战性的复制,例如仪表板。
将 CRA 添加到 Astro
段落标题 将 CRA 添加到 Astro通常情况下,你可以直接在新的 Astro 项目中渲染现有的应用程序,而无需更改应用程序的代码。
创建一个新的 Astro 项目
段落标题 创建一个新的 Astro 项目通过你的包管理器来运行 create astro
命令启动 Astro 的 CLI 向导,并选择一个新的「空」Astro 项目。
npm create astro@latest
pnpm create astro@latest
yarn create astro@latest
添加集成和依赖
段落标题 添加集成和依赖通过你的包管理器来运行 astro add
命令以添加 React 集成。如果你的应用程序使用了 Tailwind 或 MDX,你可以使用相同的命令添加多个 Astro 集成:
npx astro add reactnpx astro add react tailwind mdx
pnpm astro add reactpnpm astro add react tailwind mdx
yarn astro add reactyarn astro add react tailwind mdx
如果你的 CRA 需要其他依赖项(例如 NPM 包),那么请使用命令行单独安装它们,或者将它们手动添加到你的新 Astro 项目的 package.json
中,然后运行安装命令。请注意,并非所有的 React 依赖项都能在 Astro 中正常工作。
添加现有的应用文件
段落标题 添加现有的应用文件将现有的 Create React App (CRA) 项目的源文件和文件夹(例如 components
、hooks
、styles
等)复制到 src/
内的一个新文件夹中,并保留其文件结构,以使你的应用程序继续正常工作。请注意,所有的 .js
文件扩展名必须重命名为 .jsx
或 .tsx
。
不要包含任何配置文件。你将使用 Astro 自己的 astro.config.mjs
、package.json
和 tsconfig.json
。
将应用程序的 public/
文件夹的内容(例如静态资源)移动到 Astro 的 public/
文件夹中。
目录public/
- logo.png
- favicon.ico
- …
目录src/
目录cra-project/
- App.jsx
- …
目录pages/
- index.astro
- astro.config.mjs
- package.json
- tsconfig.json
渲染你的应用
段落标题 渲染你的应用在 index.astro
的 frontmatter 部分导入你的应用程序的根组件,然后在页面模板中渲染 <App />
组件:
---import App from '../cra-project/App.jsx';---<App client:load />
你的应用程序需要使用 客户端指令 来实现交互。在你选择启用客户端 JavaScript 之前,Astro 将把你的 React 应用程序呈现为静态 HTML。
而使用 client:load
来确保你的应用程序立即从服务器加载,或者使用 client:only="react"
来跳过服务器端渲染,完全在客户端运行你的应用程序。
有关详细信息和可用选项,请参阅我们的 配置 Astro 指南。
将 CRA 转换为 Astro
段落标题 将 CRA 转换为 Astro除了 将现有应用程序添加到 Astro,你可能也希望将应用程序本身直接转换为 Astro!
你可以在现有结构的基础上 使用 Astro 的 HTML 模板组件 以重构类似的基于组件的设计,同时导入和包含个别的 React 组件(它们本身可能是完整的应用程序!)来实现群岛交互。
每个迁移的过程都会有所不同,你可以逐步进行迁移,而不会影响你正在工作的应用程序。按照自己的节奏逐渐转换每个部分,从而使应用程序中越来越多的部分由 Astro 组件驱动。
当你转换你的 React 应用程序时,你需要决定哪些 React 组件你将会 重写为 Astro 组件。唯一的限制是 Astro 组件可以导入 React 组件,但 React 组件只能导入其他 React 组件:
---import MyReactComponent from '../components/MyReactComponent.jsx';---<html> <body> <h1>Use React components directly in Astro!</h1> <MyReactComponent /> </body></html>
相比于在 React 组件中导入 Astro 组件而言,你可以在单个 Astro 组件中使用嵌套的 React 组件。
---import MyReactSidebar from '../components/MyReactSidebar.jsx';import MyReactButton from '../components/MyReactButton.jsx';---<MyReactSidebar> <p>Here is a sidebar with some text and a button.</p> <div slot="actions"> <MyReactButton client:idle /> </div></MyReactSidebar>
在将你的 CRA 重构为 Astro 项目之前,了解 Astro 群岛 和 Astro 组件 可能会对你有所帮助。
比较:JSX 与 Astro
段落标题 比较:JSX 与 Astro比较一下如下的 CRA 组件和相对应的 Astro 组件:
import React, { useState, useEffect } from 'react';import Header from './Header';import Footer from './Footer';
const Component = () => {const [stars, setStars] = useState(0);const [message, setMessage] = useState('');
useEffect(() => { const fetchData = async () => { const res = await fetch('https://api.github.com/repos/withastro/astro'); const json = await res.json();
setStars(json.stargazers_count || 0); setMessage(json.message); };
fetchData();}, []);
return ( <> <Header /> <p style={{ backgroundColor: `#f4f4f4`, padding: `1em 1.5em`, textAlign: `center`, marginBottom: `1em` }}>Astro has {stars} 🧑🚀</p> <Footer /> </>)};
export default Component;
---import Header from "./Header.astro";import Footer from "./Footer.astro";import "./layout.css";const res = await fetch('https://api.github.com/repos/withastro/astro');const json = await res.json();const message = json.message;const stars = json.stargazers_count || 0;---<Header /><p class="banner">Astro has {stars} 🧑🚀</p><Footer /><style> .banner { background-color: #f4f4f4; padding: 1em 1.5em; text-align: center; margin-bottom: 1em; }<style>
将 JSX 文件转换为 .astro
文件
段落标题 将 JSX 文件转换为 .astro 文件下面是将 CRA(Create React App)的 .js
组件转换为 .astro
组件的一些建议:
-
将现有 CRA 组件函数返回的 JSX 作为 HTML 模板的基础。
-
将任何 CRA 或 JSX 语法更改为 Astro 或 HTML 的标准规范。这包括
{children}
和className
等。 -
将任何必要的 JavaScript,包括导入语句,移动到 「代码围栏」(
---
) 中。注意:在 Astro 中,条件性渲染内容的 JavaScript 通常直接写在 HTML 模板中。 -
使用
Astro.props
访问之前传递给 CRA 函数的任何其他属性。 -
决定是否需要将任何导入的组件转换为 Astro。你可以将它们暂时保留为 React 组件,或永久保留为 React 组件。但是,如果它们不需要交互性,你可能最终会想将它们转换为
.astro
组件! -
将
useEffect()
替换为导入语句或Astro.glob()
来查询本地文件,使用fetch()
来获取外部数据。
迁移测试
段落标题 迁移测试由于 Astro 输出原始的 HTML,因此可以使用构建步骤的输出来编写端到端测试。如果之前编写的端到端测试能够匹配 CRA 站点的标记,那么它们可能也可以直接使用。在 Astro 中,也可以导入和使用测试库(如 Jest 和 React Testing Library)来测试你的 React 组件。
了解更多详情,请参阅 Astro 的 测试指南。
参考:将 CRA 语法转换为 Astro
段落标题 参考:将 CRA 语法转换为 Astro在 Astro 中转换 CRA 导入语句
段落标题 在 Astro 中转换 CRA 导入语句将任何 文件导入 准确地更新为相对引用的文件路径。可以通过使用 导入别名 或完整写出相对路径来实现。
注意,.astro
和其他一些文件类型必须使用它们的完整文件扩展名进行导入。
---import Card from `../../components/Card.astro`;---<Card />
在 Astro 中转换 CRA 子组件属性
段落标题 在 Astro 中转换 CRA 子组件属性将任何 {children}
实例转换为 Astro 的 <slot />
。Astro 不需要将 {children}
作为函数属性来传递,它会自动在 <slot />
中渲染子组件内容。
------export default function MyComponent(props) { return ( <div> {props.children} </div> );}
<div> <slot /></div>
传递多组子元素的 React 组件可以通过使用 命名插槽 转换为 Astro 组件。
了解更多有关于 特定 <slot />
用法 的内容。
在 Astro 中转换 CRA 数据获取
段落标题 在 Astro 中转换 CRA 数据获取在 Create React App 组件中获取数据与 Astro 类似,只有一些细微的差别。
你需要移除任何副作用钩子(useEffect
)的实例,然后使用 Astro.glob()
或 getCollection()
(或 getEntryBySlug()
)从项目源代码的其他文件中获取数据。
要 获取远程数据,请使用 fetch()
。
这些数据请求是在 Astro 组件的 frontmatter 中进行的,并使用顶层的 await。
---import { getCollection } from 'astro:content';
// 从 `src/content/blog/` 目录中获取所有条目const allBlogPosts = await getCollection('blog');
// 从 `src/pages/posts/` 目录中获取所有条目const allPosts = await Astro.glob('../pages/posts/*.md');
// 获取远程数据const response = await fetch('https://randomuser.me/api/');const data = await response.json();const randomUser = data.results[0];---
了解更多有关于 使用 Astro.glob()
、 使用集合 API 查询 以及 获取远程数据 的内容。
在 Astro 中转换 CRA 样式
段落标题 在 Astro 中转换 CRA 样式你可能需要用 Astro 中其他可用的 CSS 选项来替换任何 CSS-in-JS 库(例如 styled-components)。
如有必要,将任何行内样式对象(style={{ fontWeight: "bold" }}
)转换为行内的 HTML 样式属性(style="font-weight:bold;"
)。或者,使用 Astro 的 <style>
标签来实现作用域限定的 CSS 样式。
<div style={{backgroundColor: `#f4f4f4`, padding: `1em`}}>{message}</div><div style="background-color: #f4f4f4; padding: 1em;">{message}</div>
如果已安装了 Tailwind 集成,则可以支持 Tailwind,并且不需要更改现有的 Tailwind 代码!
了解更多有关于 Astro 中的样式 的内容。
故障排除
段落标题 故障排除你的 CRA 可能可以在 Astro 中正常工作!但是,你可能需要进行微小调整,以复制现有应用程序的功能和(或)样式。
如果在文档中未找到答案,请访问 Astro 的 Discord,并在我们的支持论坛上提问!