基本介绍
Remix is a full stack web framework that lets you focus on the user interface and work back through web standards to deliver a fast, slick, and resilient user experience. People are gonna love using your stuff.
- 是一个现代化的前端框架,由Echonest团队构建,旨在为开发者提供一种更简单、更直观的方式来构建全功能的Web应用程序。它采用了React库,并结合了服务器端渲染(SSR)和客户端交互的能力,让开发者能够高效地创建高性能且用户体验优良的应用。
特点
- 简洁API - Remix的API设计得非常简洁,降低了学习曲线,让开发者可以更快地上手。
- 开箱即用的工具链 - 提供了一整套预配置的工具,如webpack、ESLint等,开发者无需花费时间配置即可开始编码。
- 易于测试 - 由于Remix的模块化结构,每个功能都独立封装,因此单元测试变得更容易。
开始
- 输入命令行
npx create-remix@latest
- 运行项目
npm run dev
目录
├─ .eslintrc.cjs
├─ .gitignore
├─ app
│ ├─ entry.client.tsx
│ ├─ entry.server.tsx
│ ├─ root.tsx
│ ├─ routes
│ │ └─ _index.tsx
│ └─ tailwind.css
├─ package-lock.json
├─ package.json
├─ postcss.config.js
├─ public
│ └─ favicon.ico
├─ README.md
├─ tailwind.config.ts
├─ tsconfig.json
└─ vite.config.ts
/app
一般存放主要的文件/app/routes
文件夹下的是存放路由entry.client.tsx
此文件是浏览器的入口点entry.server.tsx
此模块的导出是一个函数,可让您创建响应,包括 HTTP 状态、标头和 HTML,让您完全控制生成标记并将其发送到客户端的方式root.tsx
生成HTML元素文件
路由文件命名
- 在
routes
文件夹下创建的文件将会自动创建页面路由,相关的路由文件名命名规则:https://remix.run/docs/en/main/file-conventions/routes
URL 网址 | Matched Route 匹配路线 | 说明 |
---|---|---|
/ | app/routes/_index.tsx | |
/about | app/routes/about.tsx | |
/concerts/trending | app/routes/trending.tsx | |
/concerts/salt-lake-city | app/routes/$city.tsx | salt-lake-city是动态参数,可以使用params来接收,使用 $ 前缀创建它们 |
/concerts/san-diego | app/routes/$city.tsx | san-diego是动态参数,可以使用params来接收,使用 $ 前缀创建它们 |
/concerts | app/routes/concerts._index.tsx | 嵌套路由,使用 |
/concerts/mine | app/routes/concerts_.mine.tsx | 没有布局嵌套的URL,选择在父段上使用尾随下划线来退出嵌套 |
/login | app/routes/_auth.login.tsx | 与一组路由共享布局,而不向 URL 添加任何路径段 |
/en/categories | app/routes/($lang).categories.tsx | 将路线段括在括号中将使该段成为可选的 |
/beef/and/cheese | app/routes/$.tsx | 可以使用 "*" 键访问 splat 路由的 params 上匹配路径的值 |
/files/talks/remix-conf_old.pdf | app/routes/files.$.tsx | |
/sitemap.xml | app/routes/sitemap[.]xml.tsx | 特殊字符 |
核心数据流
Loader
此函数运行在服务器上,初始化服务器时,他向HTML文档提供数据
- 其实可以理解为RESTFUL接口中的GET请求
import { json } from "@remix-run/node";
export const loader = async ({request,context,params}) => {
return json({ ok: true });
};
request
request
是一个 Fetch API Request
对象,代表 HTTP 请求。它包含请求方法、请求头、请求体等信息。你可以使用这个对象来获取请求的详细信息或传递给其他 API 调用。
一般会使用的方法
- new URL:创建一个 URL 对象
URL
对象具有以下常用属性:href
: 完整的 URL 字符串。protocol
: URL 的协议部分(例如,http:
或https:
)。hostname
: URL 的主机名(例如,example.com
)。port
: URL 的端口号。pathname
: URL 的路径部分(例如,/path
)。search
: 查询字符串(包括开头的?
)。searchParams
: 一个URLSearchParams
对象,表示查询参数。hash
: URL 的哈希部分(包括开头的#
)。
const url = new URL('https://example.com:8000/path?name=value#hash');
console.log(url.href);
// 'https://example.com:8000/path?name=value#hash'
console.log(url.protocol);
// 'https://'
console.log(url.hostname);
// 'example.com'
console.log(url.port);
// '8000'
console.log(url.pathname);
// '/path'
console.log(url.search);
// '?name=value'
console.log(url.hash);
// '#hash'
console.log(url.searchParams);
// URLSearchParams { 'name' => 'value' }
const url = new URL(request.url);
const searchParams = new URLSearchParams(url.search);
const discount = searchParams.get('discount');
context
context
是一个上下文对象,可以在 Remix 应用程序中传递额外的数据或功能。这个参数通常由开发者在创建 Remix 应用时自定义,例如数据库连接、第三方 API 客户端等。
params
params
包含 URL 参数。这些参数通常是由路由定义中的动态片段匹配的。例如,如果路由是 /posts/:postId
,那么 params
对象将包含 postId
的值。
Components
路由模块的默认导出定义了路由匹配时将呈现的组件。
- 可以接收Loader上的数据
export default function Users() {
const data = useLoaderData<typeof loader>();
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Action
路由 action
是一个仅用于处理数据突变和其他操作的服务器函数。如果对您的路线发出非 GET
请求(DELETE
、PATCH
、POST
或 PUT
)然后在 loader
之前调用该操作。
- 其实可以理解为RESTFUL接口中的GET请求
<font style="color:rgb(67, 67, 67);">action</font>
与<font style="color:rgb(67, 67, 67);">loader</font>
具有相同的 API,唯一的区别在于调用它们的时间。这使您能够将有关数据集的所有内容共同定位在单个路由模块中:数据读取、呈现数据的组件以及数据写入:
import type { ActionFunctionArgs } from "@remix-run/node"; // or cloudflare/deno
import { json, redirect } from "@remix-run/node"; // or cloudflare/deno
import { Form } from "@remix-run/react";
import { TodoList } from "~/components/TodoList";
import { fakeCreateTodo, fakeGetTodos } from "~/utils/db";
export async function action({
request,
}: ActionFunctionArgs) {
const body = await request.formData();
const todo = await fakeCreateTodo({
title: body.get("title"),
});
return redirect(`/todos/${todo.id}`);
}
export async function loader() {
return json(await fakeGetTodos());
}
export default function Todos() {
const data = useLoaderData<typeof loader>();
return (
<div>
<TodoList todos={data} />
<Form method="post">
<input type="text" name="title" />
<button type="submit">Create Todo</button>
</Form>
</div>
);
}