前几天,我认识的人发消息:
“我发现自己在假期里试图向我的儿子解释投资回报如何通过 Zoom 发挥作用,如果我们都能够在像 Google Doc 这样的东西中工作,事情就会变得很容易”
接受挑战!
在过去的几天里,我很高兴构建了一个投资回报模拟器,我们可以在其中根据多个参数预测投资回报。
互联网上到处都是这样的网站,但在这个网站中,我想探索如何嵌入协作功能,以及它们如何将人们聚集在一起。
在本指南中,我们将了解如何在短短 10 分钟内向常规 React 应用程序添加实时协作,而无需编写任何后端代码或处理 Web 套接字。作为奖励,我们还将探索如何增强协作网站的用户体验!
该项目的完整源代码可在 GitHub 上获取
让我们开始吧!
在深入研究协作功能之前,我们需要坚实的基础。我首先创建了一个单人游戏版本,用户可以在其中输入他们的投资参数。然后,这些输入将输入计算引擎,生成并显示投资回报预测。
我使用 Bolt.new 来快速启动和运行。它给我的简洁设计以及我达到可接受起点的速度给我留下了深刻的印象。尽管领先了很多,但我仍然需要微调一些计算逻辑,并根据自己的喜好调整 UI。
单人游戏版本完成后,我将注意力转向协作。这个项目提供了一个测试 React Together 的绝佳机会,React Together 是我过去几个月在 Multisynq 开发的一个开源库。
React Together 提供了挂钩和组件,可以实现协作功能,而无需设置后端或管理套接字连接的复杂性。事实证明,实施过程很简单,尽管它揭示了一些需要改进的地方,我们将在库的未来版本中解决这些问题。
现在,让我们逐步完成向我们的应用程序添加实时协作的三个步骤!启动你的计时器吗?
第一步是将我们的应用程序包装在 React Together 上下文提供程序中。该组件在幕后处理所有状态同步和会话管理。
// src/index.tsx import { StrictMode } from 'react' import { ReactTogether } from 'react-together' import { createRoot } from 'react-dom/client' import App from './App.tsx' import './index.css' createRoot(document.getElementById('root')!).render( <StrictMode> <ReactTogether sessionParams={{ appId: import.meta.env['VITE_APP_ID'], apiKey: import.meta.env['VITE_API_KEY'], }}> <App /> </ReactTogether> </StrictMode>, )
React Together 使用 Multisynq 的基础设施进行应用程序同步,这需要 API 密钥。您可以从 multisynq.io/account 获取免费 API 密钥。别担心,这些密钥应该是公开的,因为您可以控制哪些域可以使用它们。
我们可以将 React Together 配置为在所有用户进入网站后自动将他们连接到同一个会话。事实上,这将使其成为一个两步指南,但我采用了 Google Docs 风格的方法,其中协作是选择加入的。用户保持断开连接,直到通过单击按钮明确创建或加入会话。我们将在本指南的第三步介绍会话管理!
设置好 React Together 后,下一步是同步用户之间的状态。这个过程非常简单:我们只需要将 React 的 useState 钩子替换为 React Together 的 useStateTogether 钩子即可。
useStateTogether 钩子的工作方式与 useState 类似,但需要一个额外的 rtKey 参数。此键唯一标识整个应用程序的状态,即使在 DOM 层次结构在视口之间可能不同的响应式布局中也能确保正确的同步。
以下是转换的外观:
// src/index.tsx import { StrictMode } from 'react' import { ReactTogether } from 'react-together' import { createRoot } from 'react-dom/client' import App from './App.tsx' import './index.css' createRoot(document.getElementById('root')!).render( <StrictMode> <ReactTogether sessionParams={{ appId: import.meta.env['VITE_APP_ID'], apiKey: import.meta.env['VITE_API_KEY'], }}> <App /> </ReactTogether> </StrictMode>, )
// Before import { useState } from 'react' export default function Calculator() { const [startingAmount, setStartingAmount] = useState(20000); const [years, setYears] = useState(25); const [returnRate, setReturnRate] = useState(10); const [compoundFrequency, setCompoundFrequency] = useState("annually"); const [additionalContribution, setAdditionalContribution] = useState(500); const [contributionTiming, setContributionTiming] = useState("beginning"); const [contributionFrequency, setContributionFrequency] = useState("month"); // ... }
这种方法的优点在于应用程序可以继续像以前一样工作 - 唯一的区别是现在状态更新在所有连接的用户之间同步。
最后一步是为用户添加一种创建、加入和离开协作会话的方式。我选择通过计算器上方的标题部分来实现这一点,使每个人都可以轻松看到会话控件。
React Together 通过提供四个基本钩子使这一过程变得简单:
这是标头组件的简化版本(我刚刚删除了类名称):
// After import { useStateTogether } from 'react-together' export default function Calculator() { const [startingAmount, setStartingAmount] = useStateTogether("startingAmount", 20000); const [years, setYears] = useStateTogether("years", 25); const [returnRate, setReturnRate] = useStateTogether("returnRate", 10); const [compoundFrequency, setCompoundFrequency] = useStateTogether("compoundFrequency", "annually"); const [additionalContribution, setAdditionalContribution] = useStateTogether("additionalContribution", 500); const [contributionTiming, setContributionTiming] = useStateTogether("contributionTiming", "beginning"); const [contributionFrequency, setContributionFrequency] = useStateTogether("contributionFrequency", "month"); // ... }
通过此实施,用户现在只需单击一下即可启动协作会话。当有人使用共享 URL 加入时,他们将立即看到与其他人相同的状态,所有更改都会在所有参与者之间实时同步。
就是这样,很简单,而且很有效!而且你可以在 10 分钟内完成!!
虽然基本同步运行良好,但感觉有些不对劲:页面上的元素正在“自行”更改,但没有表明是谁在进行更改。这是协作应用程序中的一个常见挑战,Google Docs 等工具通过显示其他用户正在查看和编辑的位置来解决这个问题。
真正的协作不仅仅是同步状态,还在于创造一种存在感。用户需要互相“看到”才能有效地协同工作。
我最初考虑实现共享光标,让用户看到彼此的鼠标指针。然而,这种方法给响应式 Web 应用程序带来了挑战:
相反,我专注于我们真正希望通过用户存在实现的目标:
解决方案?突出显示用户正在交互的元素。这种方法更简单、更直观,并且在所有视口尺寸上都能可靠地工作。让我们看看如何在两个关键区域实现这一点:图表选项卡和输入字段。
让我们从用户状态的简单实现开始:显示哪些用户正在查看每个图表选项卡。
为此,我们需要一种特殊的共享状态,其中每个用户都可以拥有自己的值,并且其他人都可以看到。
React Together 通过 useStateTogetherWithPerUserValues 钩子准确地提供了我们所需要的东西(是的,这实在是太拗口了!)。此挂钩的工作原理与 useStateTogether 类似,但它不是共享单个值,而是允许每个用户拥有自己的值,并且对所有参与者都可见。该钩子返回三个元素:
以下是我们如何实现此功能以在选项卡旁边显示用户头像:
// src/index.tsx import { StrictMode } from 'react' import { ReactTogether } from 'react-together' import { createRoot } from 'react-dom/client' import App from './App.tsx' import './index.css' createRoot(document.getElementById('root')!).render( <StrictMode> <ReactTogether sessionParams={{ appId: import.meta.env['VITE_APP_ID'], apiKey: import.meta.env['VITE_API_KEY'], }}> <App /> </ReactTogether> </StrictMode>, )
在上面的代码片段中,我们用 useStateTogetherWithPerUserValues 替换了 useState,应用程序再次像以前一样继续工作,但现在每个人都可以看到其他人的状态!然后我们只需要渲染我们刚刚获得的新信息即可。
此实现在每个选项卡旁边显示用户头像,从而清楚地显示哪些用户正在查看哪些图表。我们过滤掉当前用户的头像以避免冗余,因为用户不需要看到自己的状态指示器。
向输入字段添加存在指示器遵循与前面的示例类似的模式,但有一个额外的要求:我们需要跟踪用户何时开始和停止编辑。幸运的是,Ant Design 的组件为此目的提供了必要的回调。
对于每个输入字段,我想要:
以下是我们如何使用 useStateTogetherWithPerUserValues 钩子来实现这一点:
// src/index.tsx import { StrictMode } from 'react' import { ReactTogether } from 'react-together' import { createRoot } from 'react-dom/client' import App from './App.tsx' import './index.css' createRoot(document.getElementById('root')!).render( <StrictMode> <ReactTogether sessionParams={{ appId: import.meta.env['VITE_APP_ID'], apiKey: import.meta.env['VITE_API_KEY'], }}> <App /> </ReactTogether> </StrictMode>, )
虽然代码稍长,但原理很简单:我们只需要跟踪哪些用户正在编辑每个输入字段,然后渲染我们想要的可视化效果即可。
同样的方法适用于任何其他输入类型,例如下拉菜单和滑块!!
--
就是这样!有了这个完全协作的投资回报模拟器,我的朋友可以更轻松地向他的儿子解释 Zoom 上的投资回报如何发挥作用。任务完成! ✨
看到创建这种协作网站是多么容易,让我想知道当我们在线时,互联网如何让我们更加紧密地联系在一起......稍后会详细介绍!
希望您学到新的东西,如果您有任何反馈或问题,请随时与我们联系!!
编码愉快! ?
以上是在几分钟内将实时协作添加到您的 React 应用程序的详细内容。更多信息请关注PHP中文网其他相关文章!