使用 SolidJS 和 TypeScript 构建任务跟踪器
SolidJS 正迅速成为 Web 开发社区关注的焦点。凭借其直接的状态管理、细粒度的响应性和高性能,SolidJS 已成为其他 JavaScript 框架的基础。
SolidJS 是 React 开发人员一直要求的一切,在本文中,我将引导您使用 SolidJS 构建任务跟踪器。我们将涵盖以下主题:
-
为什么选择 SolidJS?
-
使用 TypeScript 设置 SolidJS 应用程序
-
安装 Bootstrap 以设计我们的 SolidJS 应用程序
-
-
使用 JSX 构建我们的任务跟踪器
-
在 SolidJS 中创建和更新状态
-
向我们的状态添加任务
-
-
在 SolidJS 中控制流和循环数据
-
在我们的嵌套状态下更新任务
-
在SolidJScreateStore中用于嵌套反应性
先决条件
要学习本教程,您需要了解 JavaScript 和 TypeScript、Node.js 模块以及前端框架中的组件。
为什么选择 SolidJS?
如果您以前使用过 React,SolidJS 看起来会非常熟悉。当 React Hooks 第一次发布时,我非常高兴,因为我认为它可以解决我们的状态管理危机。Hooks 使组件中的本地状态管理更容易,但全局状态管理仍然很复杂。
断开连接的组件仍然很难共享数据,并且出现了许多库来尝试解决状态管理问题——这增加了开发疲劳并给我们的代码库增加了不必要的复杂性。
我也在其他前端框架中看到了同样的问题;就好像全局状态管理是事后才想到的,而不是从一开始就计划好的事情。
使用 SolidJS,事情就不同了。全局状态管理就像创建状态并导出它一样简单。不需要任何复杂的设置或第三方库。
SolidJS 还使用 JSX,一种流行的类似 HTML 的 JavaScript 语法扩展。这使得处理 UI 逻辑、事件和状态更改变得简单。再加上,SolidJS 编译为纯 JavaScript,因此不需要虚拟 DOM,使其比 React 和 Angular 等框架相对更快。
SolidJS 也有一个简单的工作流程。组件只呈现一次,就像在 JavaScript 中一样,因此更容易预测代码的结果。
SolidJS 的另一个巨大优势是它建立在其他 Web 框架的肩膀上,因此它自豪地模仿了好的部分并改进了不太好的部分。
超过 20 万开发人员使用 LogRocket 来创造更好的数字体验了解更多 →
让我们继续设置我们的 SolidJS 应用程序,以逐步学习如何使用 SolidJS 构建 Web 应用程序。
使用 TypeScript 设置 SolidJS 应用程序
要在本地机器上设置 SolidJS 应用程序,您需要安装Node.js。如果您已经安装了它,在您的终端上运行以下命令应该会返回您当前的 Node.js 版本:
节点--版本
接下来,让我们通过在终端上运行以下命令来创建一个新的 SolidJS 应用程序:
npx degit solidjs/templates/ts 任务跟踪器
使用solidjs/templates/ts会生成一个 Solid/TypeScript 应用程序。对于 JavaScript,您必须将命令更改为solidjs/templates/js.
运行命令后,您应该会看到如下所示的成功消息:
> 将solidjs/templates#HEAD 克隆到任务跟踪器
现在,继续并在您选择的代码编辑器或 IDE 中打开生成的应用程序。应用程序结构如下所示:
请注意,我们的 SolidJS 应用程序使用Vite作为其默认构建工具,并使用pnpm作为默认包管理器。这些工具相结合,为组件渲染、应用程序启动时间和包管理提供了出色的开发体验。
我们的应用程序组件当前位于./src/App.tsx文件中:
来自 LogRocket 的更多精彩文章:
-
不要错过来自 LogRocket 的精选时事通讯The Replay
-
使用 React 的 useEffect优化应用程序的性能
-
在多个 Node 版本之间切换
-
了解如何使用 AnimXYZ 为您的 React 应用程序制作动画
-
探索 Tauri,一个用于构建二进制文件的新框架
-
比较NestJS 与 Express.js
-
发现TypeScript 领域中使用的流行 ORM
从“solid-js”导入类型{组件} ... 常量应用程序:组件 = () => { 返回 ( <div> ... </div> ); } 导出默认应用
首先,我们导入Component类型solid-js,然后将其用作我们App组件的类型。
SolidJS 中的组件是 JavaScript 函数。它们是可重用的,并且可以使用类似于函数参数/参数的 props 进行自定义。
在./src/index.tsx文件内部,我们渲染我们的App组件:
从“solid-js/web”导入{渲染} 从 './App' 导入应用程序 render(() => <App />, document.getElementById('root') as HTMLElement)
render()from 方法solid-js/web需要两个参数:
-
<App />返回我们组件的函数
-
一个 HTML 元素
当您导航到该./index.html文件时,您将通过标签看到根目录div和我们./src/index.tsx文件的使用:<script />
... <正文> <noscript>您需要启用 JavaScript 才能运行此应用程序。</noscript> <div id="root"></div> <script src="/src/index.tsx" type="module"></script> </正文>
要运行我们的 SolidJS 应用程序,我们必须首先通过pnpm install在终端上运行命令来安装我们的包,然后pnpm dev在开发模式下启动我们的应用程序。您应该会看到如下所示的成功消息:
vite v2.9.9 开发服务器运行在: > 本地:http://localhost:3001/ > 网络:使用 `--host` 暴露 在 378 毫秒内准备就绪。
当您导航到终端上显示的 URL 时,您应该会看到类似于以下内容的页面:
安装 Bootstrap 以设计我们的 SolidJS 应用程序
现在我们已经成功地设置了我们的 SolidJS 应用程序,让我们安装 Bootstrap 以进行样式设置,这样我们就不必为 CSS 操心了。
要安装 Bootstrap,请在终端上运行以下命令:
pnpm 安装引导程序
接下来,我们将使用以下代码行在我们的./src/index.tsx文件中导入 Bootstrap:
导入'bootstrap/dist/css/bootstrap.min.css'
我们也可以删除当前的./index.css导入,因为我们不需要它。我们的index.tsx文件现在应该如下所示:
从“solid-js/web”导入{渲染} 从 './App' 导入应用程序 导入'bootstrap/dist/css/bootstrap.min.css' render(() => <App />, document.getElementById('root') as HTMLElement)
使用 JSX 构建我们的任务跟踪器
让我们使用 JSX 来构建我们的任务跟踪器。在./src/App.tsx文件中,将您当前拥有的内容替换为:
从“solid-js”导入类型{组件} 常量应用程序:组件 = () => { 返回 ( <div class="container mt-5 text-center"> <h1 class="mb-4">做什么!</h1> <form class="mb-5 row row-cols-2 justify-content-center"> <input type="text" class="input-group-text p-1 w-25" placeholder="在此处添加任务..." id="taskInput" required /> <button class="btn btn-primary ms-3 w-auto" type="submit"> 添加任务 </按钮> </form> <div> <h4 class="text-muted mb-4">任务</h4> <div class="row row-cols-3 mb-3 justify-content-center"> <button class="btn btn-danger w-auto">X</button> <div class="bg-light p-2 mx-2">推送代码到GitHub</div> <input type="checkbox" role="button" class="form-check-input h-auto px-3" /> </div> </div> </div> ) } 导出默认应用
我们的 JSX 代码包含用于输入新任务的表单和任务部分。目前,我们使用的是硬编码数据,但我们将学习如何使我们的应用程序动态化,以便当用户在表单中输入新任务并单击提交按钮时,我们的 SolidJS 应用程序会使用新数据进行更新.
当您返回浏览器时,您的页面现在应该如下所示:
接下来,让我们学习如何在 SolidJS 中创建和管理状态。我们将通过创建一个taskList状态来做到这一点,我们还将创建用于向我们的状态添加新任务、删除它们以及更新它们的完成状态的函数。
在 SolidJS 中创建和更新状态
SolidJS 有一个createSignalHook 来创建状态。例如,让我们创建一个taskList状态来容纳我们的任务。在./src/App.tsx文件中,我们将首先为每个任务创建一个类型:
常量应用程序:组件 = () => { 类型任务 = { 文本:字符串 文本:字符串 完成:布尔 } 返回 (...) }
接下来,我们将创建我们的taskList状态:
从“solid-js”导入 { Component, createSignal } ... const [taskList, setTaskList] = createSignal([] as Task[]) ...
Hook 返回一个包含两个变量的createSignal()数组,taskList和setTaskList。与您在React Hooks 中看到的不同,这两个变量都是函数。我们调用该taskList()函数来访问我们的任务数据,并调用该setTaskList()函数来更新我们的taskList状态。
映剪辑纯净版App,新手入门级剪辑软件,做视频简单如手机P图!
向我们的状态添加任务
现在我们已经创建了我们的taskList状态,让我们创建一个用于向我们的状态添加任务的函数。我们将其命名为addTask:
const [taskList, setTaskList] = createSignal([] as Task[]) const addTask = (e: Event) => { e.preventDefault() const taskInput = document.querySelector('#taskInput') as HTMLInputElement 常量新任务:任务 = { id: Math.random().toString(36).substring(2), 文本:taskInput.value, 完成:假, } setTaskList([newTask, ...taskList()]) taskInput.value = '' }
在我们的addTask()函数内部,我们首先使用该e.preventDefault()方法来防止提交表单时的默认重新加载行为。我们还taskInput从<input />ID 为“taskInput”的元素中获取我们的信息。
对于每个新任务,我们创建一个名为newTask属性id、text和的对象completed。创建新任务时,我们的函数将使用该Math.random()方法为我们的任务 ID 生成一个随机字符串,并将默认completed值设置为false.
最后,setTaskList()将使用数组作为参数调用该函数,并附加newTask当前taskList状态。
我们还创建一个删除任务的函数:
... const deleteTask = (taskId: string) => { const newTaskList = taskList().filter((task) => task.id !== taskId) 设置任务列表(新任务列表) }
当我们deleteTask()以任务 ID 作为参数调用我们的函数时,它将过滤我们的taskList状态并返回除具有我们要删除的 ID 的任务之外的所有任务。然后,setTaskList()将使用新的任务列表作为参数调用该方法。
为了addTask()使用我们的函数,我们将在 JSX 代码中onSubmit的标记中添加一个事件侦听器,<form />只要单击提交按钮,它就会调用我们的函数。
... 返回 ( <div class="container mt-5 text-center"> <h1 class="mb-4">做什么!</h1> <form class="mb-5 row row-cols-2 justify-content-center" onSubmit={(e) => addTask(e)}> ... </form> </div> )
接下来让我们看看当用户添加新任务时如何在应用程序中显示我们的taskList数据。
在 SolidJS 中控制流和循环数据
SolidJS 有一个<For />用于循环数据的组件。虽然 JavaScriptArray.map()方法可以工作,但我们的组件将始终在taskList更新时映射状态。使用该<For />组件,我们的应用程序将只更新需要更新的 DOM 的确切部分。
让我们用这个替换我们目前在任务中的内容div:
... <div> <h4 class="text-muted mb-4">任务</h4> <对于每个={taskList()}> {(任务:任务)=>( <div class="row row-cols-3 mb-3 justify-content-center"> <button class="btn btn-danger w-auto">X</button> <div class="bg-light p-2 mx-2">{task.text}</div> <input type="checkbox" checked={task.completed} role="button" class="form-check-input h-auto px-3" /> </div> )} </对于> </div> ...
请注意我们如何将我们taskList的组件包装在<For />组件中。我们还将任务文本从“Push code to GitHub”更新为task.text我们的task参数。
我们现在可以继续使用deleteTask()我们之前创建的方法。我们将为Delete按钮添加一个onClick事件侦听器:
... <button class="btn btn-danger w-auto" οnclick={() => deleteTask(task.id)}> X </按钮> ...
如果我们转到浏览器,我们的 SolidJS 应用程序现在应该像这样工作:
在我们的嵌套状态中更新任务状态
SolidJS 有一个createStore()用于创建和管理嵌套状态的 Hook。但在我们谈论它之前,让我们看看如何更新我们createSignal()状态中的预先存在的任务。我们将在函数下创建一个名为的新toggleStatus函数deleteTask():
... const toggleStatus = (taskId: string) => { const newTaskList = taskList().map((task) => { if (task.id === taskId) { 返回 { ...任务,完成:!task.completed } } 返回任务 }) 设置任务列表(新任务列表) }
我们的toggleStatus()函数需要一个taskId参数,我们将使用它来获取我们想要标记为已完成或未完成的特定任务。我们还使用该map()方法循环遍历我们的taskList状态,如果我们找到与参数具有相同 ID 的任务taskId,我们会将其completed属性更改为与当前存在的相反的属性。所以,如果true,我们会成功false,如果false,true。
最后,我们使用该setTaskList()方法taskList用我们的新taskList数据更新状态。
在我们使用我们的toggleStatus()函数之前,让我们在 JSX 代码中添加已完成任务和未完成任务之间的区别。如果它的属性是,我们将把 Bootstrap 类“text-decoration-line-through text-success”添加到任务文本中。在我们的 JSX 代码中,就在Delete按钮下方,让我们将任务文本更新为:completedtrue
div
<div class={`bg-light p-2 mx-2 ${task.completed && 'text-decoration-line-through text-success'}`}> {任务.文本} </div>
接下来,我们将在复选框输入标签中添加一个事件监听器,只要单击它onClick,我们就会调用该方法:toggleStatus()
<输入 类型=“复选框” 检查={task.completed} 角色="按钮" class="form-check-input h-auto px-3" onClick={() => { 切换状态(task.id) }} />
我们的组件返回的 JSX 代码<App />现在应该如下所示:
<div class="container mt-5 text-center"> <h1 class="mb-4">做什么!</h1> <form class="mb-5 row row-cols-2 justify-content-center" onSubmit={(e) => addTask(e)}> <input type="text" class="input-group-text p-1 w-25" placeholder="在此处添加任务..." id="taskInput" required /> <button class="btn btn-primary ms-3 w-auto" type="submit"> 添加任务 </按钮> </form> <div> <h4 class="text-muted mb-4">任务</h4> <对于每个={taskList()}> {(任务:任务)=>( <div class="row row-cols-3 mb-3 justify-content-center"> <button class="btn btn-danger w-auto" οnclick={() => deleteTask(task.id)}> X </按钮> <div class={`bg-light p-2 mx-2 ${task.completed && 'text-decoration-line-through text-success'}`}> {任务.文本} </div> <输入 类型=“复选框” 检查={task.completed} 角色="按钮" class="form-check-input h-auto px-3" onClick={() => { 切换状态(task.id) }} /> </div> )} </对于> </div> </div>
当我们转到浏览器时,我们的 SolidJS 应用程序应该能够像这样工作:
在SolidJScreateStore中用于嵌套反应性
在结束之前,让我们看看如何使用createStoreSolidJS 中的 Hook 来创建和更新嵌套状态。与其映射我们的状态,创建一个新的任务列表,并用新列表替换我们所有的状态数据,我们可以直接使用它的 ID 更新需要更新的任务。
要使用createStoreHook,我们首先从以下位置导入它solid-js/store:
从“solid-js/store”导入 { createStore }
请注意,createSignal从 导入solid-js,而createStore从 导入solid-js/store。
接下来,我们将更新我们的taskList状态创建:
const [taskList, setTaskList] = createStore([] as Task[])
我们使用 Hook 创建的 storecreateStore()不是一个函数,不像使用 Hook创建的 store createSignal()。因此,我们将taskList代码中的所有实例修改为 justtaskList而不是taskList(). 第二个变量 ,setTaskList仍然是一个函数,我们将使用它来更新我们的商店。
让我们继续使用setTaskList()方法来修改toggleStatus()函数:
const toggleStatus = (taskId: string) => { 设置任务列表( (任务) => task.id === taskId, '完全的', (完成)=>!完成, ) }
在toggleStatus()函数中,我们将三个参数传递给setTaskList()方法:
-
获取我们要更新的特定任务的函数。在我们的例子中,我们返回与taskId参数具有相同 id 的任务
-
我们要修改的属性——completed
-
对于第三个参数,我们传递了另一个函数,该函数接收我们选择的属性的当前值并返回一个新值。在这里,我们将返回与当前相反的内容
当我们返回浏览器时,我们的应用程序应该仍能按预期工作:
结论
在本文中,我们通过构建任务跟踪器介绍了 SolidJS 的基础知识。与 Angular 和 React 等其他前端框架相比,Solid 构建 Web 应用程序的方法令人印象深刻且相对简单。通过直接编译到真实的 DOM 节点并且不需要虚拟 DOM,使用 SolidJS 构建的 Web 应用程序具有速度快的不寻常优势。
也就是说,SolidJS 仍然是新事物,与 React、Vue 和 Angular 等框架相比,它的生态系统和社区还很小,所以你很有可能第一个遇到问题或需要特定功能、库或集成。但 SolidJS 发展迅速,很多人已经开始将现有应用程序迁移到该框架。SolidJS 社区反应迅速,当您需要帮助时应该不会有任何问题。
您可以在我的 GitHub 上找到我们的任务跟踪器的存储库。我的 YouTube 频道上还有一个SolidJS 速成课程,我很乐意让你看看。如果您想保持联系,请考虑在LinkedIn上关注我。继续建设!
写了很多 TypeScript?观看我们最近的 TypeScript 聚会的录像,了解如何编写更具可读性的代码。
TypeScript 为 JavaScript 带来了类型安全。类型安全和可读代码之间可能存在紧张关系。观看录音,深入了解 TypeScript 4.4 的一些新功能