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

相关推荐
蟾宫曲3 小时前
在 Vue3 项目中实现计时器组件的使用(Vite+Vue3+Node+npm+Element-plus,附测试代码)
前端·npm·vue3·vite·element-plus·计时器
秋雨凉人心3 小时前
简单发布一个npm包
前端·javascript·webpack·npm·node.js
liuxin334455663 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
qq13267029403 小时前
运行Zr.Admin项目(前端)
前端·vue2·zradmin前端·zradmin vue·运行zradmin·vue2版本zradmin
海绵波波1073 小时前
flask后端开发(10):问答平台项目结构搭建
后端·python·flask
网络风云4 小时前
【魅力golang】之-反射
开发语言·后端·golang
魏时烟4 小时前
css文字折行以及双端对齐实现方式
前端·css
Q_19284999064 小时前
基于Spring Boot的电影售票系统
java·spring boot·后端
2401_882726485 小时前
低代码配置式组态软件-BY组态
前端·物联网·低代码·前端框架·编辑器·web
web130933203985 小时前
ctfshow-web入门-文件包含(web82-web86)条件竞争实现session会话文件包含
前端·github