使用 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。
-
运行npm i convex安装凸包
-
在项目内部,运行npx convex login,这将在浏览器中打开一个页面,使用您的 GitHub 帐户登录 Convex
-
登录后,运行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 存储的所有操作和状态。