Solid-js的定义

一个声明式、高效且灵活用于构建用户界面的 JavaScript 库(官方文档)

为什么选择Solidjs

  • 高性能 - 始终在公认的 UI 速度和内存利用率基准测试中名列前茅
  • 强大 - 可组合的反应式原语与 JSX 的灵活性相结合
  • 务实 - 合理且量身定制的 API 使开发变得有趣而简单
  • 生产力 - 人体工程学和熟悉程度使构建简单或复杂的东西变得轻而易举

优势

高性能 - 接近原生的性能,在 js-framework-benchmark 排名中名列前茅
极小的打包体积 - 编译为直接的DOM操作,无虚拟DOM,极小的运行时(类似于 Svelte),适合打为独立的 webComponent 在其它应用中嵌入
易于使用 - 近似 React 的使用体验,便于快速上手

快速开始

新建项目

> npx degit solidjs/templates/js my-app
> cd my-app
> npm i # or yarn or pnpm
> npm run dev # or yarn or pnpm

示例

将HelloWorld渲染到app容器中

import { render } from 'solid-js/web';function HelloWorld() {return <div>Hello World!</div>;
}render(() => <HelloWorld />, document.getElementById('app'))

是不是看起来非常熟悉,和 React 一样

基本概念

jsx

jsx语法

Signal

Signal 是 Solid 中最基本的反应性单元,此函数类似于 React 的 useState,但返回函数用于获取调用它获取值,而不是像 React 一样直接取得值。使用createSignal创建

const [count, setCount] = createSignal(0);

使用方式

setCount(count() + 1)
setCount((c) => c + 1); // c代表前一个值

读取Signal

<div>Count: {count()}</div>;

Effect

Signal 是可追踪的值,但它们只是等式的一半。另一半是观察者,也就是计算。最基本的计算称为 Effect,它产生副作用 —— 我们系统的输出。

可以通过从 solid-js 导入 createEffect 来创建 Effect。createEffect 接收一个函数,并监视其执行情况。createEffect 会自动订阅在执行期间读取的所有 Signal,并在这些 Signal 值之一发生变化时重新运行该函数。

createEffect(() => {console.log("The count is now", count());
});

Memo

Memo 既是是跟踪计算,类似 Effect,又是只读 Signal。由于知道对应依赖关系及其观察者,Memo 可以确保他们只对任何更改运行一次。

看一个例子

生命周期

onMount

它只是一个 Effect 调用,但你可以放心使用它,一旦所有初始渲染完成,它只会在组件中运行一次

onMount(async () => {const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`);setPhotos(await res.json());
});

onCleanup

一些框架的清理方法直接是框架的副作用或生命周期方法的返回值。由于 Solid 渲染树中的所有内容都存在于(可能是惰性的)Effect 中并且可以嵌套,因此我们将 onCleanup 设为一级方法。您可以在任何范围内调用它,它会在该范围被触发以重新求值以及最终销毁时运行。

onCleanup(() => clearInterval(timer));

流程控制

控制流大多可以用 JSX 实现相同功能,但是使用其则具有高于 JSX 的性能,Solid 可以对其进行更多优化
fallback 是在失败后的显示

Show

JSX 允许使用 JavaScript 来控制模板中的逻辑流。然而,如果没有虚拟 DOM,天真地使用诸如 Array.prototype.map 之类的东西会在每次更新时很浪费地重新创建所有 DOM 节点。相反,Reactive 库使用模板工具是很常见。在 Solid 中,我们将其封装在组件中

<Showwhen={loggedIn()}fallback={() => <button onClick={toggle}>Log in</button>}
><button onClick={toggle}>Log out</button>
</Show>

fallback 属性充当 else,在传递给 when 的条件不为 true 时显示。

For

<For each={cats()}>{(cat, i) => (<li><a target="_blank" href={`https://www.youtube.com/watch?v=${cat.id}`}>{i() + 1}: {cat.name}</a></li>)}
</For>

index 是一个 Signal,因此它可以在移动行时独立更新

Index

<Index each={cats()}>{(cat, i) => (<li><a target="_blank" href={`https://www.youtube.com/watch?v=${cat().id}`}>{i + 1}: {cat().name}</a></li>)}
</Index>

<Index><For> 具有相似的签名,除了数据项是 Signal 并且索引是固定的。

Switch

<Switch><Match> 组件类比 javaScript的Switch/case

<Switch fallback={<p>{x()} is between 5 and 10</p>}><Match when={x() > 10}><p>{x()} is greater than 10</p></Match><Match when={5 > x()}><p>{x()} is less than 5</p></Match>
</Switch>

Dynamic

<Dynamic> 可以让你将元素的字符串或组件函数传递给它,并使用提供的其余 props 来渲染组件

<Dynamic component={options[selected()]} />

除此之外,还有Portal、ErrorBoundary等组件,详情见官方文档

绑定

事件绑定

常规事件绑定

<div onMouseMove={handleMouseMove}>The mouse position is {pos().x} x {pos().y}
</div>

Solid 支持数组语法调用事件处理程序

const handler = (data, event /*...*/) => (<button onClick={[handler, data]}>Click Me</button>
);

on: 命名空间来匹配冒号后面的事件处理程序

<button on:WierdEventName={() => /* Do something */} >Click Me</button>

样式

先写一段css

/* main.module.css */
.container {width: 100px;height: 100px;background-color: green;
}
.text {font-size: 20px;color: red;
}

样式使用也与 React 非常类似,只是使用 class 而不是 className

import style from "./main.module.css";export default function Container() {return (<div class={style.container}><span class={style.text}>text</span></div>)
}

Solid 中的 style 属性接受样式字符串或对象。然而,对象形式不同于 Element.prototype.style,Solid 通过调用 style.setProperty 的封装来进行样式设置。这意味着键需要采用破折号的形式,如 background-color 而不是 backgroundColor

classList

用于设置给定的 class 是否存在, 也可以绑定响应式
下列是一个点击切换 class 的示例

import style from "./main.css";
import { createSignal } from "solid-js";export default function Container() {const [hasTextClassName, setHasTextClassName] = createSignal(false);return (<div classList={{[style.container]: true,[style.text]: hasTextClassName()}} onClick={()=> setHasTextClassName(!hasTextClassName())}>text</div>)
}

ref/ref转发

<div ref={myDiv}>My Element</div>;
<div ref={el => /* 处理 el... */}>My Element</div>
<canvas ref={props.ref} width="256" height="256" />

指令

Solid 通过 use: 命名空间支持自定义指令。但这只是 ref 一个有用的语法糖,类似于原生的绑定,并且可以在同一个元素上有多个绑定而不会发生冲突。这可以让我们更好地利用可重用 DOM 元素行为。

<div class="modal" use:clickOutside={() => setShow(false)}>Some Modal
</div>

click-outside.js

//click-outside.js
export default function clickOutside(el, accessor) {const onClick = (e) => !el.contains(e.target) && accessor()?.();document.body.addEventListener("click", onClick);onCleanup(() => document.body.removeEventListener("click", onClick));
}

Props

设置props默认值(mergeProps)

一般情况

export default function Greeting(props) {return <h3>{props.greeting || "Hi"} {props.name || "John"}</h3>
}

使用mergeProps

export default function Greeting(props) {const merged = mergeProps({ greeting: "Hi", name: "John" }, props);return <h3>{merged.greeting} {merged.name}</h3>
}

解构Props(splitProps

使用直接解构的方式,会失去响应性

export default function Greeting(props) {const { greeting, name, ...others } = props;return <h3 {...others}>{greeting} {name}</h3>
}

使用splitProps可以保持其相应行

export default function Greeting(props) {const [local, others] = splitProps(props, ["greeting", "name"]);return <h3 {...others}>{local.greeting} {local.name}</h3>
}

注意:solid中的props读取时不可以使用延展操作符,否则会失去响应式

异步

lazy

在应用中,某些组件只在使用时加载,这些组件会被单独打包,在某个时间被按需加载,solid 也提供了方法
使用 lazy 替换普通的静态 import 语句

import Component1 from "./Component1.jsx";

替换为

const Component1 = lazy(() => import("./Component1"));

由于 lazy 接接收的参数只是返回 Solid 组件的 Promise,因此,还可以在加载的时候附加一些行为

createResource

创建一个可以管理异步请求的信号。fetcher 是一个异步函数,它接受sourceif 提供的返回值并返回一个 Promise,其解析值设置在资源中。fetcher 不是响应式的,因此如果您希望它运行多次,请使用可选的第一个参数。如果源解析为 false、null 或 undefined,则不会获取。

官网在线试玩

const [data, { mutate, refetch }] = createResource(getQuery, fetchData);
// 获取值
data();
// 检查其是否加载中
data.loading;
// 检查是否出错
data.error;
// 直接设置值
mutate(optimisticValue);
// 刷新,重新请求
refetch();

Suspense

Suspense 配合异步组件使用
在尚未加载完毕时显示 fallback 中给定的内容

const Component1 = lazy(() => import("./Component1"));export default function App() {return (<Suspense fallback={<div>loading...</div>}><Component1></Component1></Suspense>)
}

更多异步

总结

  • Solid 具有高性能,并且具有极小的打包体积,适合打包为独立的模块嵌入其它项目
  • Solid 上手简单,贴合 React 或是 Vue3 开发者的使用习惯
  • Solid 中 JSX 直接返回 DOM 元素,符合直觉,并且很纯净
  • Solid 某些地方需要使用其指定的东西才能达到高性能,高性能并不是毫无代价的
  • Solid 目前使用并不多,生态有待完善

友情链接

doc、star-history 、size、homepage

Solidjs 简介相关推荐

  1. etcd 笔记(01)— etcd 简介、特点、应用场景、常用术语、分布式 CAP 理论、分布式原理

    1. etcd 简介 etcd 官网定义: A highly-available key value store for shared configuration and service discov ...

  2. Docker学习(一)-----Docker简介与安装

    一.Docker介绍 1.1什么是docker Docker是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源 Docker可以让开发者打包他们的应用以及依赖包到一个轻量级,可移植 ...

  3. 【Spring】框架简介

    [Spring]框架简介 Spring是什么 Spring是分层的Java SE/EE应用full-stack轻量级开源框架,以IOC(Inverse Of Control:反转控制)和AOP(Asp ...

  4. TensorRT简介

    TensorRT 介绍 引用:https://arleyzhang.github.io/articles/7f4b25ce/ 1 简介 TensorRT是一个高性能的深度学习推理(Inference) ...

  5. 谷粒商城学习笔记——第一期:项目简介

    一.项目简介 1. 项目背景 市面上有5种常见的电商模式 B2B.B2C.C2B.C2C.O2O B2B 模式(Business to Business),是指商家和商家建立的商业关系.如阿里巴巴 B ...

  6. 通俗易懂的Go协程的引入及GMP模型简介

    本文根据Golang深入理解GPM模型加之自己的理解整理而来 Go协程的引入及GMP模型 一.协程的由来 1. 单进程操作系统 2. 多线程/多进程操作系统 3. 引入协程 二.golang对协程的处 ...

  7. Linux 交叉编译简介

    Linux 交叉编译简介 主机,目标,交叉编译器 主机与目标 编译器是将源代码转换为可执行代码的程序.像所有程序一样,编译器运行在特定类型的计算机上,输出的新程序也运行在特定类型的计算机上. 运行编译 ...

  8. TVM Operator Inventory (TOPI)简介

    TOPI简介 这是 TVM Operator Inventory (TOPI) 的介绍.TOPI 提供了比 TVM 具有更高抽象的 numpy 风格的,通用操作和调度.TOPI 如何在 TVM 中,编 ...

  9. 计算机视觉系列最新论文(附简介)

    计算机视觉系列最新论文(附简介) 目标检测 1. 综述:深度域适应目标检测标题:Deep Domain Adaptive Object Detection: a Survey作者:Wanyi Li, ...

最新文章

  1. 通俗理解卡尔曼滤波及其算法实现(实例解析)
  2. uptime命令分析负载
  3. 移动端访问mysql_java – (可能)数百个移动客户端访问MySQL数据库的最佳方法是什么?...
  4. mongodb中分页显示数据集的学习
  5. 为什么尽量使用常量引用
  6. UE4游戏开发基础命令
  7. Gartner预测:SD-WAN将取代路由
  8. jsp输入限制正则表达式
  9. DNN Experience
  10. bzoj4403-序列统计【Lucas,组合数学】
  11. 你觉得跳广场舞的都是一群什么样的人?
  12. HTML元素分类【三种类型】
  13. H264 SPS中得到宽高的代码(java/c),测试通过
  14. Dz插件-Discuz插件-免费Discuz采集伪原创发布插件
  15. matlab怎样定义全局变量,Matlab如何定义公共变量
  16. Centos7.X安装mariadb及卸载mariadb安装mysql方法
  17. linux 查看文件内容的命令
  18. HDU 5762 Teacher Bo (水题)
  19. 学习笔记-支付宝支付
  20. Linux中fork函数详解

热门文章

  1. echarts 2.0 macarons主题安装
  2. 目标跟踪CLE绘图 OTB数据跟踪绘图 mat文件txt文件 相互转换
  3. Ectiture impossible,doublon dans une cle de la错误
  4. Win硬件 - 西部数据绿盘、蓝盘、黑盘、红盘和紫盘有什么区别?
  5. 计算机视觉(ComputerVision, CV)相关领域的网站链接
  6. U3D 游戏引擎之游戏架构脚本该如何来写
  7. 申报须知,2022年滁州市各区县高新技术企业奖励政策变化,明光市
  8. 关于手机QQ-好友的秘密 发送秘密者的位置信息获取
  9. 孩子不上学在家玩游戏打骂父母
  10. 详解如何进入、退出docker容器的方法