广告
返回顶部
首页 > 资讯 > 精选 >Remix怎么集成antd和pro-components
  • 806
分享到

Remix怎么集成antd和pro-components

2023-07-05 15:07:50 806人浏览 安东尼
摘要

本篇内容介绍了“Remix怎么集成antd和pro-components”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!要注意的问题核心要注意

本篇内容介绍了“Remix怎么集成antd和pro-components”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

要注意的问题

核心要注意的问题就是:

问题说明
模块(包)兼容性和 peer 依等问题
ssrRemix 服务端渲染支持问题

兼容性

兼容性主要体现在 React18 和其他的包的兼容性

  • 使用脚手架创建的项目默认使用 React 18,由此带来兼容性问题?

  • React 18 api 发生了变化,渲染 api 调用是否手动修改为 React18 的方式?

  • npm 的 peer 依赖安装与否?

  • 其他的依赖的兼容 React 18 的问题?

Remix 服务端渲染的支持情况

我们知道 Remix 其实基于 esbuild 很多代码都跑在服务端,所以服务端的渲染的注意点是我们要提前知道:

  • antd 支持服务端渲染

  • pro-components 不支持服务端渲染,一般用于客户渲染,因为直接使用了 window/document 等客户端才有的全局对象

  • remix-utils 工具包支持 <ClientOnly>{() => <>You Content</>}</ClientOnly> 使用组件仅仅在客户端进行渲染。

初始化项目安装必要的包

pnpm dlx create-umi@latest [your_package_name]# remix 选择默认的选项即可pnpm install remix-utils antd @ant-design/pro-components @ant-design/CSSinjs @ant-design/icons

使用新特性 v2 版本的文件路由模式

  • remix.config.js

module.exports = {  future: {    v2_routeConvention: true,  },  ignoredRouteFiles: ["**/.*"],};

添加 pro-components SettingDrawer 组件上下文

import { createContext } from "react";const SettinGContext = createContext({  theme: {},  setTheme: (theme: any) => {}});export default SettingContext;

全局配置放在 SettingContext 上下文中,需要修改和使用都基于此上下文。

root 文件修改

// typeimport type { MetaFunction } from "@remix-run/node";// coreimport {  Links,  LiveReload,  Meta,  Outlet,  Scripts,  ScrollRestoration,} from "@remix-run/react";export const meta: MetaFunction = () => ({  charset: "utf-8",  title: "New Remix App",  viewport: "width=device-width,initial-scale=1",});function Document({  children,  title = "App title",}: {  children: React.ReactNode;  title?: string;}) {  return (    <html lang="en">      <head>        <Meta />        <title>{title}</title>        <Links />        {typeof document === "undefined" ? "__ANTD__" : ""}      </head>      <body>        {children}        <ScrollRestoration />        <Scripts />        <LiveReload />      </body>    </html>  );}export default function App() {  return (    <Document>      <Outlet />    </Document>  );}
  • 将 html 单独的抽离一个 Document 组件,方便日后修改

  • 在 Document 组建中增加 __ANTD__ 方便后期替换 antd 客户端内容

增加客户端渲染入口文件:entry.client.tsx

客户端主要配合: @ant-design/cssinjs

// coresimport { startTransition, useState } from "react";import { hydrateRoot } from "react-dom/client";import { RemixBrowser } from "@remix-run/react";// components and othersimport { createCache, StyleProvider } from "@ant-design/cssinjs";import { ConfigProvider } from "antd";// contextimport SettingContext from "./settingContext";const hydrate = () => {  startTransition(() => {    const cache = createCache();    function MainApp() {      const [theme, setTheme] = useState({        colorPrimary: "#00b96b"      });      return (        <SettingContext.Provider value={{ theme, setTheme }}>          <StyleProvider cache={cache}>            <ConfigProvider              theme={{                token: {                  colorPrimary: theme.colorPrimary,                },              }}            >              <RemixBrowser />            </ConfigProvider>          </StyleProvider>        </SettingContext.Provider>      );    }    hydrateRoot(document, <MainApp />);  });};if (typeof requestIdleCallback === "function") {  requestIdleCallback(hydrate);} else {  // Safari doesn't support requestIdleCallback  // https://caniuse.com/requestidlecallback  setTimeout(hydrate, 1);}

定义 theme, setTheme 给 SettingContext 使用控制 antd 配置变化,要说明的点 StyleProvider 是用于 antd 服务端渲染 配置, 而 ConfigProvider 是 antd 主题配置的提供者。

  • 注意:React18 中不能使用 hydrateRoot api 来进行水合。

增加服务端渲染入口文件:entry.server.tsx

与 客户端一样需要 @ant-design/cssinjs 来配置 antd 的样式。

// typesimport type { EntryContext } from "@remix-run/node";// coreimport { useState } from "react";import { RemixServer } from "@remix-run/react";import { renderToString } from "react-dom/server";// componentsimport { ConfigProvider } from "antd";import { createCache, extractStyle, StyleProvider } from "@ant-design/cssinjs";// contextimport SettingContext from "./settingContext";export default function handleRequest(  request: Request,  responseStatusCode: number,  responseHeaders: Headers,  remixContext: EntryContext) {  const cache = createCache();  function MainApp() {    const [theme, setTheme] = useState({      colorPrimary: "#00b96b"    });    return (      <SettingContext.Provider value={{ theme, setTheme }}>        <StyleProvider cache={cache}>          <ConfigProvider            theme={{              token: {                colorPrimary: theme.colorPrimary,              },            }}          >            <RemixServer context={remixContext} url={request.url} />          </ConfigProvider>        </StyleProvider>      </SettingContext.Provider>    );  }  let markup = renderToString(<MainApp />);  const styleText = extractStyle(cache);  markup = markup.replace("__ANTD__", styleText);  responseHeaders.set("Content-Type", "text/html");  return new Response("<!DOCTYPE html>" + markup, {    status: responseStatusCode,    headers: responseHeaders,  });}

客户端和服务端的改造中包含了:

markup = markup.replace("__ANTD__", styleText);{typeof document === "undefined" ? "__ANTD__" : ""}

__ANTD__ 在服务端环境中替换

创建一个布局用于承载 pro-components 组件

  • /routes/_layout.tsx

// coreimport { useContext } from "react";import { Outlet } from "@remix-run/react";// componentsimport { ClientOnly } from "remix-utils";import { ProConfigProvider, SettingDrawer } from "@ant-design/pro-components";// contextimport SettingContext from "~/settingContext";export default function Layout() {  const value = useContext(SettingContext);  return (    <ClientOnly fallback={<div>Loading...</div>}>      {() => (        <ProConfigProvider>          <Outlet />          <SettingDrawer            getContainer={() => document.body}            enableDarkTheme            onSettingChange={(settings: any) => {              value?.setTheme(settings);            }}            settings={{ ...value.theme }}            themeOnly          />        </ProConfigProvider>      )}    </ClientOnly>  );}

注意:布局组件中使用有以下几个点需要注意:

  • useContext 获取当前的上下文

  • ClientOnly 组件用于仅仅在客户端渲染 Remix 组件

  • ProConfigProvider 组件为 SettingDrawer/Outlet 组件提供上下文

  • SettingDrawer 给使用当前布局 _layout 的组件提供颜色等配置

使用 antd 创建一个简单的基于 _layout._index.tsx 页面

// coreimport { JSON } from "@remix-run/node";import { useFetcher } from "@remix-run/react";// componentsimport { Button, FORM, Input, Select } from "antd";export async function action() {  return json({    title: 1,  });}const { Option } = Select;const layout = {  labelCol: { span: 8 },  wrapperCol: { span: 16 },};const tailLayout = {  wrapperCol: { offset: 8, span: 16 },};export default function Index() {  const fetcher = useFetcher();  const [form] = Form.useForm();  const onGenderChange = (value: string) => {    switch (value) {      case "male":        form.setFieldsValue({ note: "Hi, man!" });        break;      case "female":        form.setFieldsValue({ note: "Hi, lady!" });        break;      case "other":        form.setFieldsValue({ note: "Hi there!" });        break;      default:    }  };  const onFinish = (value: any) => {    const formData = new FormData();    formData.append("username", value.username);    formData.append("passWord", value.password);    fetcher.submit(formData, { method: "post" });  };  const onReset = () => {    form.resetFields();  };  const onFill = () => {    form.setFieldsValue({ note: "Hello world!", gender: "male" });  };  return (    <div>      <Form        {...layout}        form={form}        name="control-hooks"        onFinish={onFinish}        style={{ maxWidth: 600 }}      >        <Form.Item name="note" label="Note" rules={[{ required: true }]}>          <Input />        </Form.Item>        <Form.Item name="gender" label="Gender" rules={[{ required: true }]}>          <Select            placeholder="Select a option and change input text above"            onChange={onGenderChange}            allowClear          >            <Option value="male">male</Option>            <Option value="female">female</Option>            <Option value="other">other</Option>          </Select>        </Form.Item>        <Form.Item          noStyle          shouldUpdate={(prevValues, currentValues) =>            prevValues.gender !== currentValues.gender          }        >          {({ getFieldValue }) =>            getFieldValue("gender") === "other" ? (              <Form.Item                name="customizeGender"                label="Customize Gender"                rules={[{ required: true }]}              >                <Input />              </Form.Item>            ) : null          }        </Form.Item>        <Form.Item {...tailLayout}>          <Button type="primary" htmlType="submit">            Submit          </Button>          <Button htmlType="button" onClick={onReset}>            Reset          </Button>          <Button type="link" htmlType="button" onClick={onFill}>            Fill form          </Button>        </Form.Item>      </Form>    </div>  );}

_layout._index.tsx 表示使用:_layout 布局的 / 页面路由。

使用 pro-component 创建一个简单的基于 _layout._procomponents.tsx 页面

// coreimport { json } from "@remix-run/node";import { useFetcher } from "@remix-run/react";// componentsimport { Button, Form, Space } from "antd";import {  ProForm,  ProFormDependency,  ProFormSelect,  ProFormText,} from "@ant-design/pro-components";export async function action() {  return json({    title: 1,  });}const layout = {  labelCol: { span: 8 },  wrapperCol: { span: 16 },};const tailLayout = {  wrapperCol: { offset: 8, span: 16 },};export default function Index() {  const fetcher = useFetcher();  const [form] = Form.useForm();  const onGenderChange = (value: string) => {    switch (value) {      case "male":        form.setFieldsValue({ note: "Hi, man!" });        break;      case "female":        form.setFieldsValue({ note: "Hi, lady!" });        break;      case "other":        form.setFieldsValue({ note: "Hi there!" });        break;      default:    }  };  const onFinish = (value: any) => {    const formData = new FormData();    formData.append("username", value.username);    formData.append("password", value.password);    fetcher.submit(formData, { method: "post" });  };  const onReset = () => {    form.resetFields();  };  const onFill = () => {    form.setFieldsValue({ note: "Hello world!", gender: "male" });  };  return (    <div>      <Form        {...layout}        form={form}        name="control-hooks"        onFinish={onFinish}        style={{ maxWidth: 600 }}      >        <ProFormText name="note" label="Note" rules={[{ required: true }]} />        <ProFormSelect          name="gender"          label="Gender"          rules={[{ required: true }]}          fieldProps={{            onChange: onGenderChange          }}          options={[            {              label: "male",              value: "male",            },            {              label: "female",              value: "female",            },            {              label: "other",              value: "other",            },          ]}        />        <ProFormDependency name={["gender"]}>          {({ gender }) => {            return gender === "other" ? (              <ProFormText                noStyle                name="customizeGender"                label="Customize Gender"                rules={[{ required: true }]}              />            ) : null;          }}        </ProFormDependency>        <ProForm.Item {...tailLayout}>          <Space>            <Button type="primary" htmlType="submit">              Submit            </Button>            <Button htmlType="button" onClick={onReset}>              Reset            </Button>            <Button type="link" htmlType="button" onClick={onFill}>              Fill form            </Button>          </Space>        </ProForm.Item>      </Form>    </div>  );}

/procomponents 页面基本是 / 页面使用 pro-components 的改造版本。需要我们注意的是 表单联动 使用用方式不一样。

“Remix怎么集成antd和pro-components”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: Remix怎么集成antd和pro-components

本文链接: https://www.lsjlt.com/news/353169.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Remix怎么集成antd和pro-components
    本篇内容介绍了“Remix怎么集成antd和pro-components”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!要注意的问题核心要注意...
    99+
    2023-07-05
  • Remix集成antd和pro-components的过程示例
    目录正文要注意的问题兼容性Remix 服务端渲染的支持情况初始化项目安装必要的包使用新特性 v2 版本的文件路由模式添加 pro-components SettingDrawer 组...
    99+
    2023-03-24
    Remix集成antd pro-components Remix集成antd Remix集成pro-components
  • 怎么用SSSD和Realm集成Ubuntu到Samba4 AD DC
    小编给大家分享一下怎么用SSSD和Realm集成Ubuntu到Samba4 AD DC,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!要求:在 Ubuntu 上用 Samba4 创建一个活动目录架构第 1 步:初始配置 在把...
    99+
    2023-06-16
  • SpringBoot怎么设置静态资源访问控制和封装集成
    这篇文章主要讲解了“SpringBoot怎么设置静态资源访问控制和封装集成”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot怎么设置静态资源访问控制和封装集成”吧!背景最近在...
    99+
    2023-06-20
  • pytorch怎么把图像数据集进行划分成train,test和val
    这篇文章给大家分享的是有关pytorch怎么把图像数据集进行划分成train,test和val的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1、手上目前拥有数据集是一大坨,没有train,test,val的划分如...
    99+
    2023-06-15
  • springboot怎么集成easy-captcha实现图像验证码显示和登录
    这篇文章主要介绍“springboot怎么集成easy-captcha实现图像验证码显示和登录”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“springboot怎么集成easy-captcha实现图...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作