Remix 快速入门
Remix 快速入门
Remix 是一个比较新的全栈 Web 框架, 它基于 React 技术栈, 类似 Next.js. 本文仅介绍 Remix 的基本使用与一些开发过程可能遭遇的一些场景进行展开, 将同 Remix 文档的快速开始一样意简言骇.
创建项目
Remix 至少需要 nodejs 版本为 ^14.17.0
或 >=16.0.0
.
初始化一个新的 Remix 项目可以使用 npx
或 yarn create
:
npx:
npx create-remix --template remix-run/indie-stack your-project-name
yarn:
yarn create remix --template remix-run/indie-stack your-project-name
运行后会提示选择 Typescript 或 Javascript:
TypeScript or JavaScript? (Use arrow keys)
建议使用 Typescript 保证代码健壮性.
继续将会提示是否 install, 完成安装后让我们启动开发服务器:
yarn dev
路由
Remix 的路由与 Next.js 类似, 也是通过约定自动生成.
当你在 app/routes/
文件夹下创建 tsx/jsx 文件时, 它会自动生成对应的路由.
例如 app\routes\help\index.tsx
对应路由: website.com/help
,
而动态路由 app\routes\help\$id.tsx
对应路由: website.com/help/${queryId}
.
app/root.tsx
为根节点.
Remix 还支持嵌套路由, 在父级页面使用 <Outlet>
组件渲染.
举个例子父组件还是用 app\routes\help\index.tsx
, 内部结构为:
app\routes\help\index.tsx
export default function Help() {
return (
<PageWrapper>
<Header />
<Main>
<Outlet />
</Main>
</PageWrapper>
);
}
子组件即可继承外部样式与布局直接渲染数据:
app\routes\help$id.tsx
export default function HelpItem() {
const { id } = useParams();
const { data } = useLoaderData<{ data: Data }>();
if (!data.length) return <Empty type='error' title='暂无数据!' />;
return data.map((item, i) => <Item {...item} />);
}
配置链接与 meta 信息
在开发过程中我们可能会使用外部的链接或全局 CSS 样式,
remix 通过导出默认方法 links
创建链接:
// 链接集合
export const links: LinksFunction = () => [
{ rel: 'stylesheet', href: GlobalStyle },
{ rel: 'icon', href: '/help/favicon.ico' },
];
SSR 最初就是为了解决 SEO 而诞生的, 所以 meta 信息的配置必不可少.
同上通过导出默认方法 meta
创建 meta 信息配置:
// 常见的元信息集合
export const meta: MetaFunction = () => ({
charset: 'utf-8',
title: 'AntPro',
keywords: 'AntPro',
});
CSS-in-JS libraries 配置
建议使用
@emotion/styled
, 开箱即用无需配置且没有水合警告.
使用 CSS-in-JS 库, 例如 Styled Components 需要"双重渲染", 以便在服务器渲染期间从组件树中提取样式,
并且我们需要在 app/root.tsx
根组件中放置一个占位符来控制样式插入:
app/root.tsx
export default function App() {
return (
<html lang='en'>
<head>
<Meta />
<Links />
{typeof document === 'undefined' ? '__STYLES__' : null}
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}
然后在控制 HTTP 响应的文件 app/entry.server.tsx
渲染样式, 例如:
import type { EntryContext } from '@remix-run/node';
import { RemixServer } from '@remix-run/react';
import { renderToString } from 'react-dom/server';
import { ServerStyleSheet } from 'styled-components';
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const sheet = new ServerStyleSheet();
// 渲染html为string
let markup = renderToString(sheet.collectStyles(<RemixServer context={remixContext} url={request.url} />));
const styles = sheet.getStyleTags();
// 替换占位符
markup = markup.replace('__STYLES__', styles);
responseHeaders.set('Content-Type', 'text/html');
return new Response('<!DOCTYPE html>' + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}
使用 Styled Components 时可能会遇到水合警告, 这个不会影响页面的样式展示.
数据获取
remix 基于 Web Fetch API 建立, 通过在 server 端获取数据来完成 browser 的快速渲染.
在 server 端获取数据后通过导出 loader
加载器将数据推送至页面,
再通过 useLoaderData
获取, 例如刚刚的 help\$id.tsx
组件,
它就通过 useLoaderData
数据来获取数据 data
:
app\routes\help$id.tsx
// 服务端获取数据后将数据推送至页面
export const loader: LoaderFunction = async ({ params }) => {
if (!params.id) return [];
try {
return getHelpItem(params.id);
} catch (error) {
return [];
}
};
export default function HelpItem() {
const { id } = useParams();
// 获取数据
const { data } = useLoaderData<{ data: Data }>();
if (!data.length) return <Empty type='error' title='暂无数据!' />;
return data.map((item, i) => <Item {...item} />);
}