Quickstarters
如何构建一个 Remix 前端并将其连接到后端?
20 分
在本教程中,您将使用 remix 构建一个待办事项列表应用程序,并将其连接到 back4app 上的托管后端服务。 本逐步指南旨在帮助您掌握基本的 crud 操作,并使用 remix 设计动态用户界面。 构建全栈应用程序涉及设置前端和后端。通过使用 back4app,您可以利用可扩展的后端即服务(baas),因此您可以专注于创建引人入胜的用户体验,而不必陷入服务器配置的麻烦。 back4app 提供了一个现成的数据库、身份验证、云函数和 sdk,以实现无缝集成。凭借这些功能,您可以快速原型设计、构建和部署您的 remix 应用程序。 关键要点 通过遵循本教程,您将: 使用行业标准工具初始化一个现代 remix 项目。 使用 parse sdk 将您的 remix 前端连接到 back4app 后端。 实现 crud 操作以管理您的 待办事项列表 。 将您的 remix 应用程序容器化,并通过 back4app web 部署进行部署。 先决条件 在您开始之前,请确保您拥有以下内容: node js 和 npm 已安装在您的系统上。通过在终端中运行 node v 和 npm v 来验证。 基本的 remix 知识 , 包括路由、加载器和操作。熟悉 react 概念会有所帮助,因为 remix 是基于 react 的。 一个 back4app 账户 用于配置和管理您的后端服务。如果您还没有,请在 back4app https //www back4app com/ 注册。 有了这些工具,您就可以创建您的 remix 应用程序并将其与强大的后端集成。 项目设置 首先,设置您的本地开发环境并初始化您的 remix 项目。这将确保您为应用程序提供一个干净高效的基础。 首先使用以下命令安装 remix 项目。将 todo app 替换为您想要的项目名称: npx create remix\@latest todo app 导航到您的新项目目录: cd todo app 运行开发服务器以验证一切正常: npm run dev 打开终端中提供的 url,以确认您的 remix 应用程序成功运行。 在 back4app 上设置 todo 后端 back4app 提供一个强大的、由 parse 驱动的托管后端。您将为您的任务创建一个数据模型,这将作为您的待办事项应用程序的支柱。 创建您的后端应用程序 登录到您的 back4app 控制面板 https //www back4app com/ 并点击 "创建新应用。" 为您的应用程序命名(例如, todoremixapp ) 并选择 nodejs/parse 作为后端类型。 在 "数据库" > "浏览器" 部分,点击 "创建一个类" 并选择 "自定义。" 将类命名为 任务 并设置其类级别权限以允许公共读取和写入(您可以稍后细化这些设置)。 向 任务 类添加以下字段: 标题 (字符串) – 任务的名称。 描述 (字符串) – 关于任务的详细信息。 完成 (布尔值) – 表示任务是否完成。 截止日期 (日期) – 任务的截止日期。 点击 "保存" 以完成模式。 将 back4app 与 remix 集成 您将使用 parse javascript sdk 将您的 remix 应用程序与 back4app 连接。通过运行以下命令安装 sdk npm install parse 接下来,在您的 remix 应用程序中配置 parse。打开文件 app/root tsx 并在顶部添加以下初始化代码。将 'your application id' 和 'your javascript key' 替换为您在 back4app 控制面板中的凭据(在 应用设置 > 安全性与密钥 ) // app/root tsx import parse from "parse"; import react from "react"; const parse app id = 'your application id'; const parse js key = 'your javascript key'; const parse server url = 'https //parseapi back4app com/'; parse initialize(parse app id, parse js key); (parse as any) serverurl = parse server url; 确保在加载器函数运行时 parse 完全初始化,特别是在服务器端。 将此代码添加到您的 layout 函数中,位于 root tsx 文件中。 // app/root tsx export function layout({ children } { children react reactnode }) { react useeffect(() => { if (typeof window !== 'undefined') { parse initialize(parse app id, parse js key); (parse as any) serverurl = "https //parseapi back4app com/"; } }, \[]); // rest of the layout function } 此设置允许您的 remix 路由和操作与您的 back4app 后端无缝交互。 使用 remix 构建前端 在配置好后端后,您将使用 remix 构建待办事项列表界面。这涉及创建路由、加载器和操作来处理数据获取和变更。 构建你的路由 在 remix 中,每个路由对应于 app/routes 目录下的一个文件。打开 app/routes/ index tsx 并添加以下代码以定义页面的结构和数据操作: // app/routes/ index tsx import { json, redirect } from "@remix run/node"; import { useloaderdata, form } from "@remix run/react"; import as parse from "parse"; export const loader = async () => { if (typeof window === "undefined") { try { const response = await fetch( "https //parseapi back4app com/classes/task", { headers { "x parse application id" "your application id", "x parse javascript key" "your javascript key", }, } ); const data = await response json(); return json({ tasks data results map((task) => ({ id task objectid, task })), }); } catch (error) { console error("error fetching tasks ", error); return json({ tasks \[] }); } } else { try { const task = parse object extend("task"); const query = new parse query(task); const results = await query find(); const tasks = results map((task) => ({ id task id, task tojson() })); return json({ tasks }); } catch (error) { console error("error fetching tasks ", error); return json({ tasks \[] }); } } }; export const action = async ({ request }) => { const formdata = await request formdata(); const actiontype = formdata get("actiontype"); // parse server details const parseserverurl = "https //parseapi back4app com"; const headers = { "x parse application id" "your application id", "x parse javascript key" "your javascript key", "content type" "application/json", }; try { if (actiontype === "add") { const title = formdata get("title"); const description = formdata get("description"); // create task using rest api const response = await fetch(`${parseserverurl}/classes/task`, { method "post", headers, body json stringify({ title, description, completed false, }), }); if (!response ok) { throw new error(`failed to add task ${response status}`); } } else if (actiontype === "toggle") { const id = formdata get("id"); // first get the current task to check its completed status const getresponse = await fetch(`${parseserverurl}/classes/task/${id}`, { headers, }); if (!getresponse ok) { throw new error(`failed to get task ${getresponse status}`); } const task = await getresponse json(); const updateresponse = await fetch( `${parseserverurl}/classes/task/${id}`, { method "put", headers, body json stringify({ completed !task completed, }), } ); if (!updateresponse ok) { throw new error(`failed to update task ${updateresponse status}`); } } else if (actiontype === "delete") { const id = formdata get("id"); const deleteresponse = await fetch( `${parseserverurl}/classes/task/${id}`, { method "delete", headers, } ); if (!deleteresponse ok) { throw new error(`failed to delete task ${deleteresponse status}`); } } return redirect("/"); } catch (error) { console error("error processing action ", error); return json({ error error message }, { status 400 }); } }; export default function todoroute() { const { tasks } = useloaderdata(); return ( \<div classname="container"> \<h1>to do list\</h1> \<form method="post" classname="form"> \<input type="hidden" name="actiontype" value="add" /> \<input type="text" name="title" placeholder="task title" required /> \<input type="text" name="description" placeholder="description" required /> \<button type="submit">add task\</button> \</form> \<div classname="tasks"> {tasks length === 0 ? ( \<p>no tasks available\</p> ) ( tasks map(task => ( \<div key={task id} classname={`task item ${task completed ? "completed" ""}`}> \<h3>{task title}\</h3> \<p>{task description}\</p> \<form method="post"> \<input type="hidden" name="actiontype" value="toggle" /> \<input type="hidden" name="id" value={task id} /> \<button type="submit">{task completed ? "undo" "complete"}\</button> \</form> \<form method="post"> \<input type="hidden" name="actiontype" value="delete" /> \<input type="hidden" name="id" value={task id} /> \<button type="submit">delete\</button> \</form> \</div> )) )} \</div> \</div> ); } 此路由使用remix的加载器和操作从back4app获取任务,并处理用户交互,如添加、切换和删除任务。 为您的 remix 应用程序设置样式 在 app/global css 中创建一个 css 文件,以定义您应用程序的基本外观和感觉: / app/global css / container { max width 600px; margin 40px auto; padding 0 20px; text align center; font family sans serif; } container h1 { margin bottom 20px; } form { display flex; flex direction column; align items center; gap 10px; margin bottom 20px; } form input\[type="text"] { width 80%; max width 400px; padding 8px; font size 1rem; } form button { padding 8px 16px; cursor pointer; font size 1rem; border none; background color #eaeaea; transition background color 0 2s ease; } form button\ hover { background color #ccc; } tasks p { font size 1rem; } task item { display flex; flex direction column; align items center; gap 12px; border 1px solid #ccc; border radius 6px; padding 15px; margin 10px 0; background color #fafafa; text align center; transition background color 0 2s ease; } task item completed h3, task item completed p { text decoration line through; color #888; } task item h3 { margin 0; font size 1 1rem; } task item p { margin 0; font size 1rem; } task item button { padding 6px 12px; border none; background color #eaeaea; cursor pointer; font size 0 9rem; } task item button\ hover { background color #ccc; } @media (min width 600px) { task item { flex direction row; } } 通过添加以下内容在您的 app/root tsx 中导入 css 文件: // app/root tsx import " /global css"; 您的 remix 应用程序现在具有一个功能齐全的待办事项列表界面,可以与 back4app 的后端进行交互。 在 back4app 上容器化和部署您的 remix 应用程序 back4app web 部署为您的应用程序提供了一个容器化环境。您将把您的 remix 应用程序打包到 docker 容器中并进行部署。 为生产配置 remix 在容器化之前,将您的 remix 应用程序构建为生产就绪的包: npm run build 创建 dockerfile 在项目根目录下创建一个 dockerfile ,内容如下 \# stage 1 build the remix app from node 18 alpine as builder workdir /app copy package json package lock json / run npm install copy run npm run build \# stage 2 serve the app using a lightweight node server from node 18 alpine workdir /app copy from=builder /app/build /build copy from=builder /app/package json / run npm install production expose 3000 cmd \["npm", "run", "start"] 此 dockerfile 构建您的 remix 项目并使用最小的 node js 运行时为生产做好准备。 构建和测试您的 docker 容器 在本地构建您的 docker 镜像 docker build t todo remix frontend 运行容器以测试部署 docker run p 8080 3000 todo remix frontend 访问 http //localhost 8080 在您的浏览器中以验证您的 remix 应用程序是否正常运行。 通过 back4app web 部署 将您的项目推送到 github git init git add git commit m "initial commit for back4app deployment" git branch m main git remote add origin \<your github repository url> git push u origin main 然后,登录到 back4app web 部署 https //www back4app com/containers 并按照以下步骤操作 点击 "创建新应用" 并命名您的项目。 选择 github 仓库 并授权 back4app。 选择您的 todo remix 仓库。 选择 dockerfile 部署 并确认构建设置。 点击 "部署" 开始构建。 部署后,通过 back4app 仪表板监控您的容器。您可以查看日志、管理构建和配置自定义域名。 测试和调试您的应用程序 一旦部署,确保您的应用程序按预期功能运行。以下是验证前端与后端集成的方法 api 连接: 打开浏览器的开发者控制台(f12),在添加、切换或删除任务时检查网络请求。 数据持久性: 通过 ui 添加任务并刷新页面以确认它们已保存。在 task 类下的 back4app 数据库浏览器中验证更改。 crud 操作: 测试切换完成状态和删除任务。如果出现问题,请检查控制台和 api 日志。 边缘情况处理: 尝试提交空输入以确保您的验证有效。 最佳实践和优化建议 遵循这些建议以增强安全性、性能和可扩展性: 优化 api 调用: 使用批量请求并在查询中仅选择必要字段。 环境变量: 将敏感密钥(应用程序 id 和 javascript 密钥)存储在一个 env 文件中并安全引用它们。 访问控制: 实施动态 acl 以限制数据修改仅限于经过身份验证的用户。 云代码: 将复杂逻辑卸载到 back4app 云代码中,以提高性能和安全性。 结论 您已经成功构建了一个完整栈的待办事项应用程序,并将其连接到 back4app 后端。 本教程指导您初始化 remix 项目,集成管理服务以进行后端交互,并将您的应用程序容器化以进行部署。 现在您的应用程序已上线,请考虑通过高级用户管理、实时更新或第三方集成来扩展其功能。 有关更多指导,请查看 back4app 文档 https //www back4app com/docs 和 remix 资源。

