当前位置: 首页 > news >正文

使用 Convex 进行状态管理的指南

像 React 这样的现代前端框架让开发人员的状态管理变得更加容易,但是使用像 Convex 这样的解决方案进行状态管理却让它变得更加容易。在 React 中,组件的状态决定了 UI 的外观,虽然管理应用程序的状态变得相对简单,但全局状态概念仍然是开发人员的痛点。

例如,考虑跟踪与全局状态一起工作的金融交易的应用程序,所有客户端都可以实时更改和观察。此类应用程序很难开发,因为开发人员需要在应用程序之间同步状态并处理 ACID 属性。

Convex旨在通过提供包括数据存储、检索和突变在内的全栈解决方案来解决这个问题,所有这些都内置在用于全局状态管理的 SDK 中。它的无服务器方法是高效的,并且是一个高度可扩展的平台。Convex 是一个开发者优先的平台,其反应式架构与 React 非常吻合,并且 SDK 还支持乐观更新和订阅等功能。

在本教程中,我们将使用 Convex 构建一个全栈 Next.js 应用程序,用于全局状态管理。我们还将实现凸函数来查询和更新数据。在本教程结束时,我们将把最终的应用程序部署到 Vercel — 随时使用这个GitHub 存储库跟随本演练。

  • 设置 Next.js 项目

  • 设置凸

  • 使用 Convex 添加状态管理

    • 定义架构

    • 实现凸函数

    • 用凸函数连接组件

    • 管理凸

  • 保护应用程序

    • 创建 Auth0 应用程序

    • 设置 Auth0

    • 将 Auth0 与凸集成

  • 部署到 Vercel

先决条件

您需要在计算机上安装 Node.js、npm 或 yarn,以及像 VS Code 这样的代码编辑器。您还需要一个 GitHub 帐户才能与 Convex 一起使用。

设置 Next.js 项目

该应用程序将允许用户查看现有帖子的列表并提交新的博客帖子。一篇博文将包含标题、正文和作者姓名。

首先,运行以下命令来设置一个新的 Next.js 项目:

npx create-next-app@latest凸示例 --typescript

在代码编辑器中打开项目并更新pages/index.tsx文件以显示表单以创建博客文章:

// pages/index.tsx
从“下一个”导入类型 { NextPage }
从“下一个/头”导入头
从 '../styles/Home.module.css' 导入样式
从“反应”导入 { useCallback, useState }
​
常量主页:NextPage = () => {
  const [作者,setAuthor] = useState('')
  const [title, setTitle] = useState('')
  const [body, setBody] = useState('')
​
  常量 createPost = async () => {
    // TODO: 在数据库中创建一个新帖子
    console.log({作者、标题、正文})
    // 提交后重置输入
    设置作者('')
    集合体('')
    设置标题('')
  }
​
  返回 (
      <div className={styles.container}>
        <头部>
          <title>Next.js 凸面</title>
          <meta name="description" content="由创建下一个应用生成" />
          <link rel="icon" href="/favicon.ico" />
        </头>
​
        <主类名={styles.main}>
          <h1 className={styles.title}>
            欢迎使用{' '} 访问 <a href="https://nextjs.org">Next.js</a>
            <a href="https://convex.dev">凸</a>
          </h1>
          <输入
              类型={'文本'}
              价值={标题}
              占位符={'标题'}
              className={styles.inputStyles}
              onChange={(event) => setTitle(event.target.value)}
          />      
          <输入
              类型={'文本'}
              价值={作者}
              占位符={'作者'}
              className={styles.inputStyles}
              onChange={(event) => setAuthor(event.target.value)}
          />
          <文本区域
              价值={正文}
              行={5}
              placeholder={'帖子正文'}
              className={styles.inputStyles}
              onChange={(event) => setBody(event.target.value)}
          />
          <button className={styles.button} onClick={createPost}>
            创建帖子
          </按钮>
        </main>
      </div>
  )
}
​
导出默认主页

更新styles/Home.module.css如下:

/* 样式/Home.module.css */
。容器 {
  填充:0 2rem;
  显示:弯曲;
  弹性方向:列;
}
​
。主要的 {
  填充:4rem 0;
  弹性:10;
  显示:弯曲;
  弹性方向:列;
  证明内容:中心;
  对齐项目:居中;
}
​
。按钮 {
  字体大小:1rem;
  字体粗细:800;
  光标:指针;
  保证金:0.5rem;
  填充:0.5rem;
  文字装饰:无;
  边框:1px 实心#eaeaea;
  边框半径:10px;
  过渡:颜色 0.15s 缓动,边框颜色 0.15s 缓动;
  宽度:200px;
}
​
.button:悬停,
.button:焦点,
.按钮:活动{
  颜色:#0070f3;
  边框颜色:#0070f3;
}
​
.inputStyles {
  宽度:300px;
  边距:10px 自动;
}

运行npm run dev以启动应用程序,然后http://localhost:3000/在 Web 浏览器中打开。


超过 20 万开发人员使用 LogRocket 来创造更好的数字体验了解更多 →


创建新帖子的表格已准备就绪。现在,您必须实现使用 Convex 保存和读取数据的逻辑。

设置凸

Convex 提供了一个可以在项目中使用的 JavaScript SDK。

  1. 运行npm i convex安装凸包

  2. 在项目内部,运行npx convex login,这将在浏览器中打开一个页面,使用您的 GitHub 帐户登录 Convex

  3. 登录后,运行npx convex init以初始化 Convex 项目,convex.json并.env.local进行配置。此命令还将创建一个convex/目录以将函数写入

(注意:此命令将提示您输入项目名称)

最后,更新pages/_app.tsx以添加ConvexProvider到完整的应用程序中。这ConvexProvider将允许您在整个应用程序中使用 Convex 提供的 React 钩子。

// 页面/_app.tsx
导入'../styles/globals.css'
从“下一个/应用程序”导入类型 { AppProps }
​
从 'convex/react' 导入 { ConvexProvider, ConvexReactClient }
从'../convex.json'导入conveconfig
常量凸 = 新的 ConvexReactClient(convexConfig.origin)
​
功能 MyApp({ 组件, pageProps }: AppProps) {
  返回 (
      <ConvexProvider 客户端={convex}>
        <组件 {...pageProps} />
      </ConvexProvider>
  )
}
​
导出默认 MyApp

使用 Convex 添加状态管理

在项目中设置 Convex 后,是时候创建数据模型并将前端与数据库连接起来了。

定义架构

在convex/文件夹中,创建一个新文件 ,schema.ts来定义博客文章的架构。该函数将在 Convex 内defineTable创建一个表。posts

// 凸/schema.ts
从'凸/模式'导入{defineSchema,defineTable,s}
​
导出默认defineSchema({
  帖子:定义表({
    标题:s.string(),
    作者:s.string(),
    正文:s.string(),
  }),
})

现在,运行npx convex codegen为posts模式生成类型定义以改进代码完成。这将允许您将帖子引用为Document<'posts'>.

实现凸函数

凸函数允许前端以两种方式与数据库通信:查询和变异。

这些函数是从目录中的文件导出的convex,它们被部署为无服务器函数以执行数据库交互。

前端需要阅读可用的帖子。为此,创建一个新文件;convex/getPosts.ts. 此文件导出一个查询函数,该函数返回posts数据库中的所有可用数据。

// 凸/getPosts.ts
从'./_generated/server'导入{查询}
从'./_generated/dataModel'导入{文档}
​
导出默认查询(异步({ db}):Promise<Document<'posts'>[]> => {
  返回等待 db.table('posts').collect()
})

在convex/文件夹中,创建一个名为addPost.ts. 该文件导出一个变异函数以允许用户向数据库添加新帖子。该函数接受一个post对象作为参数。

// 凸/addPost.ts
从'./_generated/server'导入{突变}
​
导出默认突变(
  异步 (
    { D b },
    帖子:{作者:字符串;正文:字符串;标题:字符串}
  ) => {
    等待 db.insert('posts', post)
  }
)

运行npx convex push以生成类型定义并将函数部署到 Convex。

来自 LogRocket 的更多精彩文章:

  • 不要错过来自 LogRocket 的精选时事通讯The Replay

  • 使用 React 的 useEffect优化应用程序的性能

  • 在多个 Node 版本之间切换

  • 了解如何使用 AnimXYZ 为您的 React 应用程序制作动画

  • 探索 Tauri,一个用于构建二进制文件的新框架

  • 比较NestJS 与 Express.js

  • 发现TypeScript 领域中使用的流行 ORM


用凸函数连接组件

Convex 提供useQuery并useMutation使用上面实现的功能与数据库交互的钩子。

将useMutation钩子添加到Home组件并更新createPost函数以使用发布数据调用addPost突变函数。

// pages/index.tsx
从“下一个”导入类型 { NextPage }
从“下一个/头”导入头
从 '../styles/Home.module.css' 导入样式
从“反应”导入 { useCallback, useState }
从“../convex/_generated/react”导入 {useMutation};
​
常量主页:NextPage = () => {
  const addPost = useMutation('addPost')
​
  const [作者,setAuthor] = useState('')
  const [title, setTitle] = useState('')
  const [body, setBody] = useState('')
​
  常量 createPost = async () => {
    等待 addPost({ 正文, 作者, 标题});
    // 提交后重置输入
    设置作者('')
    集合体('')
    设置标题('')
  }
​
  返回 (
      // 返回组件
  )
}
​
导出默认主页

添加useQuery挂钩以从数据库中获取和显示帖子列表。useQuery钩子将在加载数据时返回,undefined之后会返回一个帖子列表。

// pages/index.tsx
从“下一个”导入类型 { NextPage }
从“下一个/头”导入头
从 '../styles/Home.module.css' 导入样式
从“反应”导入 { useCallback, useState }
从“../convex/_generated/react”导入 {useMutation, useQuery};
​
常量主页:NextPage = () => {
  常量帖子 = useQuery('getPosts')
  const addPost = useMutation('addPost')
​
  const [作者,setAuthor] = useState('')
  const [title, setTitle] = useState('')
  const [body, setBody] = useState('')
​
  常量 createPost = async () => {
    等待 addPost({ 正文, 作者, 标题});
    // 提交后重置输入
    设置作者('')
    集合体('')
    设置标题('')
  }
​
  返回 (
      <div className={styles.container}>
        <头部>
          <title>Next.js 凸面</title>
          <meta name="description" content="由创建下一个应用生成" />
          <link rel="icon" href="/favicon.ico" />
        </头>
​
        <主类名={styles.main}>
          <h1 className={styles.title}>
            欢迎使用{' '} 访问 <a href="https://nextjs.org">Next.js</a>
            <a href="https://convex.dev">凸</a>
          </h1>
          {帖子?(
              <>
                <p className={styles.description}>
                  {'帖子总数:'} {posts.length}
                </p>
​
                <ul>
                  {posts.map((post) => (
                      <li key={post._id.toString()}>{post.title}</li>
                  ))}
                </ul>
              </>
          ) : (
              '正在加载帖子...'
          )}
          <输入
              类型={'文本'}
              价值={标题}
              占位符={'标题'}
              className={styles.inputStyles}
              onChange={(event) => setTitle(event.target.value)}
          />      
          <输入
              类型={'文本'}
              价值={作者}
              占位符={'作者'}
              className={styles.inputStyles}
              onChange={(event) => setAuthor(event.target.value)}
          />
          <文本区域
              价值={正文}
              行={5}
              placeholder={'帖子正文'}
              className={styles.inputStyles}
              onChange={(event) => setBody(event.target.value)}
          />
          <button className={styles.button} onClick={createPost}>
            创建帖子
          </按钮>
        </main>
      </div>
  )
}
​
导出默认主页

您的应用程序现已准备就绪!打开http://localhost:3000以查看它的实际效果:

您会注意到,每当您创建新帖子时,帖子列表都会自动更新。

由于 Convex 全局状态的端到端反应性,这种行为是可能的;每当数据更改时,使用查询的每个组件都会更新。

管理凸

运行npx convex dashboard以登录Convex 仪表板以管理您的应用程序数据、查看日志并查看函数执行和读/写的指标。

搜盘器App,全网主流网盘平台资源搜索,支持十大网盘搜索!

保护应用程序

保持应用程序数据的安全至关重要,Convex 使用身份提供者简化了数据保护。Convex 为 Auth0 提供了开箱即用的一流支持,您可以立即进行设置。

创建 Auth0 应用程序

登录到您的 Auth0 仪表板并创建一个新的单页 Web 应用程序。如果您还没有帐户,可以在 Auth0 上注册一个免费帐户。

从这个新应用程序的设置页面复制域和客户端 ID并保存以备后用。

在应用程序设置页面中,添加http://localhost:3000Allowed Callback URLs字段,如下所示。这将允许http://localhost:3000在开发期间使用 Auth0 登录。

设置 Auth0

首先运行npm i @auth0/auth0-react在您的项目中安装 Auth0。

然后,运行npx convex auth add以将 Auth0 作为身份提供者添加到 Convex。此命令将提示您输入之前复制的域和客户端 ID 。

components/在项目的根目录创建一个名为的新文件夹,并添加一个名为Login.tsxLogin 组件的新文件,该组件具有一个提示用户登录的按钮。

// 组件/Login.tsx
从“@auth0/auth0-react”导入 { useAuth0 }
​
导出函数登录(){
  const { isLoading, loginWithRedirect } = useAuth0()
  如果(正在加载){
    返回 <button className="btn btn-primary">加载中...</button>
  }
  返回 (
    <main className="py-4">
      <h1 className="text-center">凸聊天</h1>
      <div className="text-center">
        <跨度>
          <button className="btn btn-primary" onClick={loginWithRedirect}>
            登录
          </按钮>
        </span>
      </div>
    </main>
  )
}

更新以pages/_app.tsx替换。ConvexProvider``ConvexProviderWithAuth0

导入'../styles/globals.css'
从 'convex/react-auth0' 导入 { ConvexProviderWithAuth0 }
从“凸/反应”导入 { ConvexReactClient }
从'../convex.json'导入conveconfig
从“下一个/应用程序”导入 { AppProps }
从'../components/Login'导入{登录}
​
常量凸 = 新的 ConvexReactClient(convexConfig.origin)
常量 authInfo = 凸配置.authInfo[0]
​
功能 MyApp({ 组件, pageProps }: AppProps) {
    返回 (
        <ConvexProviderWithAuth0
            客户={凸}
            authInfo={authInfo}
            已登录={<登录 />}
        >
            <组件 {...pageProps} />
        </ConvexProviderWithAuth0>
    )
}
​
导出默认 MyApp

现在,当您打开应用程序时http://localhost:3000,您将看到一个登录按钮,而不是发布表单。

将 Auth0 与凸集成

现在您已经配置了 Auth0,您可以保护突变功能。该mutation函数提供认证信息作为auth对象。突变现在将addPost拒绝任何未经身份验证的请求。

// 凸/addPost.ts
从'./_generated/server'导入{突变}
​
导出默认突变(
    异步 (
        {分贝,身份验证},
        帖子:{作者:字符串;正文:字符串;标题:字符串}
    ) => {
      常量身份 = 等待 auth.getUserIdentity()
      如果(!身份){
        throw new Error('调用 addPosts 时不存在身份验证!')
      }
      等待 db.insert('posts', post)
    }
)

您还可以更新前端的代码以使用登录用户的名称作为作者字段:

// pages/index.tsx
从“下一个”导入类型 { NextPage }
从“下一个/头”导入头
从 '../styles/Home.module.css' 导入样式
从“反应”导入 { useCallback, useState }
从“../convex/_generated/react”导入 {useMutation, useQuery};
从“@auth0/auth0-react”导入 {useAuth0};
​
常量主页:NextPage = () => {
  常量 {用户} = useAuth0()
  常量帖子 = useQuery('getPosts')
  const addPost = useMutation('addPost')
​
  const [title, setTitle] = useState('')
  const [body, setBody] = useState('')
​
  常量 createPost = async () => {
    如果(用户?。名称){
      等待 addPost({ body, author: user.name, title});
    }
    // 提交后重置输入
    集合体('')
    设置标题('')
  }
​
  返回 (
      <div className={styles.container}>
        <头部>
          <title>Next.js 凸面</title>
          <meta name="description" content="由创建下一个应用生成" />
          <link rel="icon" href="/favicon.ico" />
        </头>
​
        <主类名={styles.main}>
          <h1 className={styles.title}>
            欢迎使用{' '} 访问 <a href="https://nextjs.org">Next.js</a>
            <a href="https://convex.dev">凸</a>
          </h1>
          {帖子?(
              <>
                <p className={styles.description}>
                  {'帖子总数:'} {posts.length}
                </p>
​
                <ul>
                  {posts.map((post) => (
                      <li key={post._id.toString()}>{post.title}</li>
                  ))}
                </ul>
              </>
          ) : (
              '正在加载帖子...'
          )}
          <输入
              类型={'文本'}
              价值={标题}
              占位符={'标题'}
              className={styles.inputStyles}
              onChange={(event) => setTitle(event.target.value)}
          />
          <文本区域
              价值={正文}
              行={5}
              placeholder={'帖子正文'}
              className={styles.inputStyles}
              onChange={(event) => setBody(event.target.value)}
          />
          <button className={styles.button} onClick={createPost}>
            创建帖子
          </按钮>
        </main>
      </div>
  )
}
​
导出默认主页

部署到 Vercel

要部署应用程序,请将您的代码(包括convex.json)推送到 GitHub 上的存储库并将其链接到您的Vercel 帐户:

将 build 命令替换为npx convex push && next build在部署时将最新功能推送到 Convex,并CONVEX_ADMIN_KEY从以下位置添加环境变量.env.local:

部署应用程序后,复制部署 URL ( .vercel.app):

将 URL 添加到Auth0 应用程序设置中的允许回调 URL列表中。http://localhost:3000

结论

您的应用程序现在部署在 Vercel 上。在本教程中,我们了解了全局状态管理以及如何使用 Convex 部署具有状态管理的 Next.js 应用程序。

我们还了解了如何使用 Auth0 保护应用程序并将其部署到 Vercel。您可以扩展上述应用程序以使用乐观更新和索引等高级功能,使其更快。

您可以立即免费试用 Convex,并在他们的文档中阅读有关使用它的更多信息。

LogRocket:全面了解生产 Next.js 应用程序

调试 Next 应用程序可能很困难,尤其是当用户遇到难以重现的问题时。如果您对监控和跟踪状态、自动显示 JavaScript 错误以及跟踪缓慢的网络请求和组件加载时间感兴趣,请尝试 LogRocket。

LogRocket就像一个用于网络和移动应用程序的 DVR,几乎可以记录下一个应用程序上发生的所有事情。无需猜测问题发生的原因,您可以汇总并报告问题发生时应用程序所处的状态。LogRocket 还监控您的应用程序的性能,并使用客户端 CPU 负载、客户端内存使用情况等指标进行报告。

LogRocket Redux 中间件包为您的用户会话增加了一层额外的可见性。LogRocket 记录来自 Redux 存储的所有操作和状态。

相关文章:

  • 卷积神经网络参数解读
  • IP 地址及其应用(计算机网络)
  • poi-tl(word模板渲染)
  • Java线程
  • 【Flink读写外部系统】Flink自定义kafka分区并输出
  • 【云原生】学习K8s的扩展技能(CRD)
  • Chapter05 修炼python基本功:条件语句和循环
  • 彻底掌握Makeifle(三)
  • 手机抓取蓝牙日志btsnoop的方法汇总(Android一直补充中)
  • 【Vue 开发实战】实战篇 # 30:实现一个可动态改变的页面布局
  • [单片机框架][drivers层][cw2015/ADC] fuelgauge 硬件电量计和软件电量计(一)
  • 【iVX 开发 - 入门】开发环境、应用对象树介绍(含操作演示)
  • CTFshow 代码审计
  • 19-Django REST framework-DRF工程搭建
  • CSP-S信息学奥赛考试大纲(提高级)
  • JavaScript-如何实现克隆(clone)函数
  • 03Go 类型总结
  • idea + plantuml 画流程图
  • JAVA_NIO系列——Channel和Buffer详解
  • java多线程
  • JS+CSS实现数字滚动
  • Koa2 之文件上传下载
  • Linux各目录及每个目录的详细介绍
  • PAT A1092
  • win10下安装mysql5.7
  • Xmanager 远程桌面 CentOS 7
  • 给新手的新浪微博 SDK 集成教程【一】
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 浅谈sql中的in与not in,exists与not exists的区别
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • ​第20课 在Android Native开发中加入新的C++类
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • (0)Nginx 功能特性
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (十三)Maven插件解析运行机制
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (学习日记)2024.01.19
  • (转)http协议
  • .bat批处理(一):@echo off
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .net web项目 调用webService
  • .net 微服务 服务保护 自动重试 Polly
  • .NET与java的MVC模式(2):struts2核心工作流程与原理
  • /etc/skel 目录作用
  • [ CTF ] WriteUp- 2022年第三届“网鼎杯”网络安全大赛(白虎组)
  • [20150707]外部表与rowid.txt
  • [BUUCTF NewStarCTF 2023 公开赛道] week3 crypto/pwn
  • [C#基础知识]专题十三:全面解析对象集合初始化器、匿名类型和隐式类型
  • [c++] 自写 MyString 类
  • [CentOs7]图形界面