SolidJS介绍的详细指南

1,852 阅读8分钟

简介

SolidJS 是不断增长的 JavaScript 框架列表中的一个新成员。但它并不是您普通的、日常的框架。SolidJS有一些相当有趣的功能,给竞争者带来了激烈的热度。

SolidJS框架由Ryan Carniato创建,于2018年开源,但最近以其 "细粒度反应性 "的卖点获得了一些人气。

SolidJS与React的理念几乎完全相同,但有几个例外。例如,没有虚拟DOM,以及只渲染一次组件。这些特性有助于用SolidJS构建的应用程序拥有极快的速度,并使其成为当今最快的JavaScript框架之一。

在本教程中,我们将探索 SolidJS 如何工作。为此,我们将建立一个 "待办事项 "示例应用程序,以展示这个伟大的框架所能提供的功能。

开始学习

有两种方法可以开始使用 SolidJS。首先是使用他们的在线 REPL,当您想快速建立原型时,这很有用。第二种是通过克隆 SolidJS 团队制作的预先存在的模板。

我们将采用后一种方法,因为它对本指南的目的更方便。

有两个可用的模板,即vanilla JavaScript版本或TypeScript版本。在这个介绍中,我们将使用vanilla JavaScript版本。

要开始使用该模板,请在终端运行以下命令:

# Create a solid app from the template
npx degit solidjs/templates/js solid-todo

# Change directory to project folder
cd solid-todo

# Install dependencies
npm i # or yarn install

# Start local server
npm run dev # or yarn dev

在最后一条运行本地开发服务器的命令执行完毕后,在浏览器上进入http://localhost:3000/,查看正在运行的应用程序。

blank solidjs app

Solid 组件

所有的JavaScript框架都是建立在组件的概念上。组件是一个应用程序的小隔断,像一个表单、一个输入字段或一个页脚。

这里有一个示例Solid 组件。

#App.jsx
import styles from "./App.module.css";
function App() {
  return (
    <div class={styles.App}>
      <header class={styles.header}>
        <img src={logo} class={styles.logo} alt="logo" />
        <p>
          Edit src/App.jsx and save to reload. </p> <a class={styles.link} href="https://github.com/solidjs/solid" target="_blank" rel="noopener noreferrer" > Learn Solid </a> </header> </div> ); } export default App;

就像React一样,Solid 组件是用JSX编写的。正如您在上面的代码块中所看到的,SolidJS 组件基本上是一个巨大的 JavaScript 函数,它返回 HTML 和 JavaScript 代码的混合,被称为 JSX。

信号

信号是 SolidJS 中反应性的基础。它们包含值,每当该值发生变化时,它们就会在被使用的每个实例中自动更新。

要创建一个信号,首先我们需要从solid-js 导入createSignal 并在我们的组件中使用它:

import {createSignal} from "solid-js"

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

createSignal 接受两个值,一个getter和一个setter。第一个值是一个返回当前值的函数,而不是值本身。

这意味着每当我们需要访问当前值时,我们要这样做:

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

商店

商店是 SolidJS 处理嵌套反应性的方式。商店的返回值是一个代理对象,其属性可被跟踪。

我们可以像这样创建和使用一个商店。

# First import createStore at the top of your component
import { createStore } from "solid-js/store"

# 
 const [todos, setTodos] = createStore({
        items: [
            { text: "Go skydiving", id: 3 },
            { text: "Go surfing", id: 2, },
            { text: "Climb Everest", id: 1 }
        ],
        counter: 4,
  })

const addTodoItem = (input) => {
        const title = input.value;
        if (!title.trim()) return;
        setTodos({
            items: [{ text: title, id: todos.counter }, ...todos.items],
            counter: todos.counter + 1
        });
        input.value = "";
    }

return (
      <div>
        <input type="text" ref={input} 
          placeholder="What do you have to do today?" name="todo"
          onKeyDown={(e) => {
            if (e.key === "Enter") {
              addTodoItem(input);
                  }
            }}>
        </input>
        <ul>
          {todos.items.map(i => (
             <li>{i.text}</li>
           ))}
          </ul>
        </div>
);

上面的代码是完整演示的一个小样本。一个输入字段将被呈现在屏幕上,当用户通过输入任务并点击 "回车 "进行交互时,"待办 "项目的列表将被更新并呈现在一个列表中。

从存储器中访问任何值只能通过存储器中的一个属性来完成,而不是通过使用顶层状态,这就是为什么我们在第17行使用todos.items ,而不是todos 来传播items 数组。

生命周期方法

生命周期方法是内置于 SolidJS 的特殊方法,用于在组件在 DOM 中的持续时间内对其进行操作。SolidJS 有几个生命周期,如onMountonCleanup

onMount 生命周期是在我们需要在组件最初渲染时运行一段代码时使用的。

# First import onMount at the top of your component
import { onMount } from "solid-js"
import { createStore } from "solid-js/store"

  const [todos, setTodos] = createStore({
      items: [],
      counter: 3,
  })

  onMount(() => {
      setTodos("items", [
          { text: "Go swimming", id: 2 },
          { text: "Go scuba diving", id: 1 }
      ])
  })

从上面的代码块中,注意到商店已经被修改,它的内容被移到了onMount 生命周期的钩子上。当组件第一次渲染时,items 数组被填满了我们的待办事项列表。

onCleanup 生命周期方法被用来在有副作用的函数之后进行任何必要的清理。

import { createSignal, onCleanup } from "solid-js";

function Counter() {
  const [count, setCount] = createSignal(0);
  const timer = setInterval(() => setCount(count() + 1), 1000);
    onCleanup(() => clearInterval(timer));

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

控制流

Solid JS 有一堆内置的帮助器,用于在需要执行各种操作时,如
条件性渲染或在一个数组列表中循环。这些帮助器可避免在每次更新时浪费地重新创建所有的 DOM 节点。

这里有一个代码块,演示了它们的使用方法。

import { Show, Switch, Match, Portal, For } from "solid-js";

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

<For each={todos.items}>{(todo) =>
  <li>
    <div class={styles.todoItem}>
        {todo.text}
      <i class="fa fa-minus-circle" onClick={() => {
        removeTodoItem(todo.id);
        }}>
      </i>
    </div>
  </li>
    }
</For>

<Portal>
  <div class="popup">
    <h1>Popup</h1>
    <p>Some text you might need for something or other.</p>
  </div>
</Portal>

<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>

让我们看一下上面的代码块中发生了什么。

Show 有条件地显示或隐藏元素,For 循环浏览一个项目列表,Portal 在应用程序的正常流程之外插入元素,Switch 根据某些条件渲染元素。

创建我们的视图

我们将开始为我们的待办事项应用程序创建各种视图。总的来说,我们将创建两个新的组件:一个Todolist.jsxAbout.jsx 组件,以及一个用于Todolist.jsx 组件的样式表Todolist.module.css

要做到这一点,首先在项目的根目录src 创建一个components 文件夹,并创建上述组件。

依次运行下面的命令来实现上述说明。

# navigate to the src folder
cd src
#create the components folder
mkdir components
#navigate to the components folder
cd components
#create the Todolist and About component and stylesheet
touch Todolist.jsx Todolist.module.css About.jsx

待办事项列表组件

Todolist.jsx 组件将包含输入字段和用户记录的所有待办事项的列表。

用以下代码更新Todolist.jsx 组件。

//Todolist.jsx

import styles from "./Todolist.module.css"
import { For, onMount } from "solid-js"
import { createStore } from "solid-js/store"

function TodoList() {
    let input;
    const addTodoItem = (input) => {
        const title = input.value;
        if (!title.trim()) return;
        setTodos({
            items: [{ text: title, id: todos.counter }, ...todos.items],
            counter: todos.counter + 1
        });
        input.value = "";
    }

    const removeTodoItem = (index) => {
        setTodos('items', (t) => t.filter((item) => item.id !== index))
    }
    onMount(() => {
        setTodos("items", [
            { text: "Go swimming", id: 2 },
            { text: "Go scuba diving", id: 1 }
        ])
    })
    const [todos, setTodos] = createStore({
        items: [],
        counter: 3,
    })
    return (
        <>
            <div class={styles.container}>
                <input type="text" ref={input} 
                    placeholder="What do you have to do today?" name="todo"
                    onKeyDown={(e) => {
                        if (e.key === "Enter") {
                            addTodoItem(input);
                        }
                    }}>
                </input>
                <ul class={styles.todoList}>
                    <For each={todos.items}>{(todo) =>
                        <li>
                            <div class={styles.todoItem}>
                                {todo.text}
                                <i class="fa fa-minus-circle" onClick={() => {
                                    removeTodoItem(todo.id);
                                }}></i>
                            </div>
                        </li>
                    }
                    </For>
                </ul>
            </div>
        </>
    );
}
export default TodoList

下面,让我们为Todolist.jsx 组件添加CSS样式。

// Todolist.module.css
.container {
    background: #fff;
  }
  .todoList {
    margin: 0;
    padding: 0;
    list-style-type: none;
  }

  .todoList li {
    padding: 20px;
    font-size: 1.3em;
    background-color: #E0EDF4;
    border-left: 5px solid #3EB3F6;
    margin-bottom: 2px;
    color: #3E5252;
  }
  input {
    width: calc(100% - 40px);
    border: 0;
    padding: 20px;
    font-size: 1.3em;
    background-color: #323333;
    color: #687F7F;
  }
  li .todoItem{
    display:flex;
    justify-content: space-between;
  }
  .todoItem i{
    cursor: pointer;
  }

About 组件

要创建about 组件,将以下代码添加到About.jsx

function About() {
  return (
    <div>
      <h1>About Page</h1>
        <div>
          <p>This is an about page created to demonstrate routing in Solid JS. Lorem ipsum dolor sit amet consecteturadipisicing elit. Tenetur, omnis?
          </p>
          <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Maiores deserunt neque ad nihil! Ut fugit mollitia voluptatum eaque. Impedit repudiandae aut eveniet eum. Nisi, quisquam enim ut, illo ipsum unde error a voluptates nobis, corporis mollitia aliquam magnam. Ipsam veniam molestias soluta quae fugiat ipsum maiores laboriosam impedit minus quisquam!
          </p>
        </div>
    </div>
    );
}
export default About;

路由

就像其他框架一样,SolidJS 有它自己处理路由的方式,那就是使用户在网站上的各个页面之间移动。

要在 SolidJS 中实现路由,我们首先要安装它。

yarn add solid-app-router
#OR
npm i solid-app-router

接下来,我们将配置路由,并创建用户可以用来在页面之间移动的链接。

要做到这一点,让我们移动到我们的App.jsx 文件,删除所有的标记,并用下面的代码来代替它。

//App.jsx
import styles from "./App.module.css";
import { Router, Routes, Route, Link } from "solid-app-router";
import { lazy } from "solid-js";

const Todolist = lazy(() => import("./components/Todolist"));
const About = lazy(() => import("./components/About"));

function App() {
  return (
    <>
      <Router>
        <div class={styles.app}>
          <Link href="/">Link to Home Page</Link>
          <Link href="/about">Link to About Page</Link>
          <Routes>
            <Route path="/" element={<Todolist />} />
            <Route path="/about" element={<About />} />
          </Routes>
        </div>
      </Router>
    </>
  );
}
export default App;

在导入我们的全局样式表后,我们从 solid-app-router 中导入Router,Routes,Route, 和Link ,以使我们的路由器配置工作得以进行。接下来,我们从 SolidJS 中导入lazy ,以帮助我们懒散地加载我们的路由。

在利用懒惰加载功能的同时导入路由的代码如下。

const Todolist = lazy(() => import("./components/Todolist"));

接下来,我们要在Router 标签之间包裹我们的应用程序,并将我们的路由定义为这样。

<Routes>
  <Route path="/" element={<Todolist />} />
  <Route path="/about" element={<About />} />
</Routes>

然后,我们需要添加导航链接,以便用户能够在路由之间切换。

<Link href="/">Link to Home Page</Link>
<Link href="/about">Link to About Page</Link>

让我们更新全局样式表上的样式,App.module.css

body, html {
  margin: 0;
  height: 100%;
}
.app {
  width: 100%;
}
body {
  background-color: #EEEEEE;
  font-family: 'Montserrat', sans-serif;
  padding: 50px 50px 0 50px;
}
nav {
  padding: 20px 20px 20px 0;
}
nav a {
  padding: 10px;
  text-decoration: none;
  background: #fff;
  border-radius: 3px;
  color: rgb(0, 110, 255);
  font-weight: bold;
  margin-right: 15px;
}

这就是我们的应用程序现在的样子。

to do sample app complete

sample to do app about page

结语

我们已经经历了 SolidJS 的一些基本功能,并成功地建立了一个小型的待办事项列表应用程序,演示了其中的一些功能。还有许多有趣的功能无法在此介绍中讨论,所以请随时查看Solid JS 文档网站以获得更多信息。