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 的获取等问题。

相关推荐
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法5 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼6 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte6 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc