Remix 多页面数据流与 axios 的单页面的数据流的区别

一、开始之前

💛本文适合对 Remix 感兴趣的同学

  • Remix 基于服务端渲染的多页面,数据流与前后端分离的 spa 数据流有所不同。
  • Remix 开发基于全栈开发,数据真实的修改操作基本通过表单在服务端完成。
  • 基于 axios 等库,前后端分离项目,axios 在与服务器交互的过程中产生了重要的作用。

二、axios 的数据流

  • 基于 axios 封装请求 api 请求函数。
  • axios 获取数据一般在组件生命后周期的挂载完毕之后的阶段。
  • axios 基于拦截器,在请求前和请求后对请求进行拦截处理,这些操作在前后端分离项目中都十分实用。

简单的封装:

ts 复制代码
import axios from 'axios';

const instance = axios.create({
  baseURL: 'https://localhost:3000/api,
  timeout: 5000,
});

instance.interceptors.request.use(
  (config) => {
    // 在请求发送之前做些什么,例如添加 headers、转换数据等
    return config;
  },
  (error) => {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

instance.interceptors.response.use(
  (response) => {
    // 对响应数据做些什么,例如提取数据或处理错误等
    return response.data;
  },
  (error) => {
    // 对响应错误做些什么
    return Promise.reject(error);
  }
);

// 每个 API 对应一个函数
export const getPost = async (postId) => {
  try {
    const response = await instance.get(`/posts/${postId}`);
    return response;
  } catch (error) {
    throw new Error(error.message);
  }
};

export const getUser = async (userId) => {
  try {
    const response = await instance.get(`/users/${userId}`);
    return response;
  } catch (error) {
    throw new Error(error.message);
  }
};

以 React function component 为例:

ts 复制代码
import React, { useEffect, useState } from 'react';
import { getPost, getUser } from './api';

const YourComponent = () => {
  const [postData, setPostData] = useState(null);
  const [userData, setUserData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const postResult = await getPost(1);
        setPostData(postResult);

        const userResult = await getUser(1);
        setUserData(userResult);
      } catch (err) {
        setError(err.message);
      }
    };

    fetchData();
  }, []);

  return (
    <div>
      {error && <p>发生错误: {error}</p>}
      {postData && (
        <div>
          <h2>Post: {postData.title}</h2>
          <p>{postData.body}</p>
        </div>
      )}
      {userData && (
        <div>
          <h2>User: {userData.name}</h2>
          <p>Email: {userData.email}</p>
        </div>
      )}
    </div>
  );
};

export default YourComponent;

三、Remix 数据流

Remix 提供的数据流,基于服务端渲染和表单提交:

  • loader.useLoaderData 获取页面输出数据
  • action/useActionData 用于表单提交

Remix 是一个基于 React SSR 的多页面全栈框架,可以在页面渲染之前获取数据,然后再提供给前端渲染页面内容,这样就不再需要 xhr/fetch/axios 等工具在 React 获取数据,并页面刷新 useLoaderData 会重新获取数据。

四、Remix 录入数据

Remix 提供了强大的表单能力, Remix 中表单需要包裹在 form 相关的组件中

表单组件

  • 原生 form 组件
  • Remix 内置 Form 组件
ts 复制代码
import type { ActionFunctionArgs } from "@remix-run/node";

import { useFetcher } from "@remix-run/react";
import { Form } from "@remix-run/react";
import { json } from "@remix-run/node";

export const action = async ({ request }: ActionFunctionArgs) => {
  const method = request.method;
  const data = await request.formData();
  const title = formData.get('title')
  return json({title})
}

function NewEvent() {
  return (
    <Form action="/events" method="post">
      <input name="title" type="text" />
    </Form>
  );
}

是 form 元素的包装器,在 url 修改和向历史堆栈中添加数据非常有用。

  • useFetchers 的 Form 组件
ts 复制代码
import type { ActionFunctionArgs } from "@remix-run/node";

export const action = async ({ request }: ActionFunctionArgs) => {
  const method = request.method;
  const data = await request.formData();
  const data1 = formData.get('key')
  return json({data1})
}

function SomeComponent() {
  const fetcher = useFetcher();
  return (
    <fetcher.Form method="post" action="/some/route">
      <input type="text" />
    </fetcher.Form>
  );
}

特点:没有导航的行为。

  • 第三方 Form 组件

也可以在 antd Form/ProForm 中配合 onFinish 函数直接使用。

表单提交

  • 默认提交

大多数情况下,对于简单的表单,可以直接提交 formData 即可,不需要额外的 js 代码吗,在 action 函数解析 POST 方法和 POST 对应的表单数据。

  • useFetcher 提交
ts 复制代码
import type { ActionFunctionArgs } from "@remix-run/node";

import { useFetcher } from "@remix-run/react";
import { Form } from "@remix-run/react";
import { json } from "@remix-run/node";

export const action = async ({ request }: ActionFunctionArgs) => {
  const method = request.method;
  const data = await request.formData();
  const title = formData.get('title')
  return json({title})
}

export function SomeComponent() {
  const fetcher = useFetcher();
  return <fetcher.Form method="post" action="/some/route">
      <input name="title" type="text" />
    </fetcher.Form>
}
  • useSubmit 提交
ts 复制代码
import { useSubmit } from "@remix-run/react";

function SomeComponent() {
  const submit = useSubmit();
  return (
    <Form
      onChange={(event) => {
        submit(event.currentTarget);
      }}
    />
  );
}

提交 json

提交表单有一个重要的缺陷:如果数据有数组。获取到的表单数据解析需要额外的编译。

ts 复制代码
import { useSubmit } from "@remix-run/react";

export const action = async ({ request }: ActionFunctionArgs) => {
  const method = request.method;
  const dataJson = await request.json();
  
  return json({})
}

function SomeComponent() {
  const submit = useSubmit();
  return (
    <Form
      onChange={async (event) => {
        await submit(values, { method: "POST", encType: "multipart/form-data" });
      }}
    />
  );
}

submit 函数中,需要配置 encTypemultipart/form-data

五、小结

axios 符合单页面的操作流,但是在 Remix 依然可以用,Remix 中更加符合多页面的服务端渲染流,同时也减少了请求的封装。

这里绝对不是否定 Axios 的价值,axios 是一个前后端通用的请求库,其拦截器功能更是巧妙设计,在基于 Token 的授权设计中使用更为常见。

在 Remix 中对于路由的数据流有自己的处理方式,符合服务端渲染和表单提交的 web 规范。Remix 提交表单时存在深层数组的问题,此时 action 中获取表单数据并不好处理,提交时可以指定为 json 模式, 在 action 解析时,可以直接获取 json 数据,简化了表单的 formData 的获取等问题。

相关推荐
大怪v10 小时前
AI抢饭?前端佬:我要验牌!
前端·人工智能·程序员
新酱爱学习10 小时前
字节外包一年,我的技术成长之路
前端·程序员·年终总结
小兵张健10 小时前
开源 playwright-pool 会话池来了
前端·javascript·github
IT_陈寒13 小时前
Python开发者必知的5大性能陷阱:90%的人都踩过的坑!
前端·人工智能·后端
codingWhat14 小时前
介绍一个手势识别库——AlloyFinger
前端·javascript·vue.js
代码老中医14 小时前
2026年CSS彻底疯了:这6个新特性让我删掉了三分之一JS代码
前端
不会敲代码114 小时前
Zustand:轻量级状态管理,从入门到实践
前端·typescript
踩着两条虫14 小时前
VTJ.PRO 双向代码转换原理揭秘
前端·vue.js·人工智能
扉川川14 小时前
OpenClaw 架构解析:一个生产级 AI Agent 是如何设计的
前端·人工智能
远山枫谷14 小时前
一文理清页面/组件通信与 Store 全局状态管理
前端·微信小程序