内置组件
Show
在React中,如果某个组件是否显示是根据state来控制,或许会
import { useState } from 'react'
function BoolControl() {
const [show, setShow] = useState(false)
return (
<div>
<button onClick={() => setShow(prevState => !prevState)}>点我</button>
{show && <div>你看得见吗?</div>}
</div>
)
}
在SolidJS中,提供了Show组件来实现这样的效果。当然,不是说必须使用Show组件,上面的写法仍然是支持的,不过我个人认为下面这样写语义上更清晰一些。
import { createSignal, Show } from "solid-js";
function BoolControl() {
const [show, setShow] = createSignal(false)
return (
<div>
<button onClick={() => setShow(prevState => !prevState)}>点我</button>
<Show when={show()}>
<div>你看得见吗?</div>
</Show>
</div>
)
}
在Show组件中有when这个属性,这个属性就是用来控制Show的children是否显示的。另外它还有一个属性fallback 这个接收的是JSX.Element,当when为false的时候,就显示fallback的内容。
Switch
在写组件的时候,一般来说使用Show组件基本上已经够用来实现,if或者if-else的情况。但是有些时候还是需要用到类似于switch-case的情况的,又或者是if-elseif-elseif...这样的情况。比如是Status不同的时候,要显示当前状态它们颜色不同,或者显示一些可交互的组件等等。这个时候就需要用到Switch,比如下面这样写
import {createSignal, Match, Switch} from "solid-js";
enum Status {
NotApplied,
ToAudit,
Fail,
Passed
}
function operation() {
const [status, setStatus] = createSignal(Status.NotApplied);
return (
<Switch>
<Match when={status() === Status.NotApplied}>
<button onClick={() => console.log("打开申请弹窗")}>去申请</button>
<button onClick={() => console.log("打开申请要求")}>查看申请条件</button>
</Match>
<Match when={status() === Status.ToAudit}>
<button onClick={() => console.log("显示当前流程")}>查看当前流程</button>
<button onClick={() => console.log("显示当前流程")}>查看当前流程</button>
</Match>
<Match when={status() === Status.Passed || status() === Status.Fail}>
<button onClick={() => console.log("显示申请结果")}>查看申请结果</button>
</Match>
</Switch>
)
}
Switch要与Match搭配使用,Switch也有fallback属性,当所有条件都不匹配的时候,就会显示fallback的内容,也就是说它相当于default的效果。如果没有fallback,也没有满足任何条件,就是什么都不显示。
Dynamic
虽然Switch挺好用的,但是有些时候要切换的组件非常的多,后续可能还会继续增加。那么如果使用Switch就需要经常修改,而且代码非常的长,不好维护。这个时候就会想到使用object或者map,经组件保存起来,然后根据名称显示对应的组件,这个时候就要用到了Dynamic,用法如下(样例来自SolidJs官网)
import { Dynamic } from "solid-js/web";
import { createSignal, For } from "solid-js";
const RedThing = () => <strong style="color: red">Red Thing</strong>;
const GreenThing = () => <strong style="color: green">Green Thing</strong>;
const BlueThing = () => <strong style="color: blue">Blue Thing</strong>;
const options = {
red: RedThing,
green: GreenThing,
blue: BlueThing
}
function ColorComponent() {
const [selected, setSelected] = createSignal("red");
return (
<>
<select value={selected()} onInput={e => setSelected(e.currentTarget.value)}>
<For each={Object.keys(options)}>{
color => <option value={color}>{color}</option>
}</For>
</select>
<Dynamic component={options[selected()]} />
</>
);
}
For
循环一个数组,然后创建出对应的组件,这是经常用到的。在React里面就是直接使用数组的map来实现。 在SolidJS还可以使用For,比如下面代码这样
import { createSignal, For } from "solid-js";
function ForExample(){
const [lans, setLans] = createSignal(["JAVA", "Rust", "C", "Javascript", "Typescript"])
return (
<ul>
<For each={lans()}>
{
(lan, i) => (
<li>
{i()}.{lan}
</li>
)
}
</For>
</ul>
)
}
For有each这个属性,它就是接收一个数组的。然后children是一个函数,这个函数的参数是当前数组项和当前索引,返回的是JSX.Element。其实这里让我们知道,children的类型其实可以是任意,主要看的就是组件怎么处理。 另外它也有fallback,接收的也是JSX.Element,当each时null,false,undefined,空数组的时候。就显示fallback的内容。
还有React和Vue的开发者大家可能发现了,li标签没有key,要注意在SolidJS中这是没必要的。
Index
它和For的很像,上面修改后如下
import {createSignal, Index} from "solid-js";
function ForExample(){
const [lans, setLans] = createSignal(["JAVA", "Rust", "C", "Javascript", "Typescript"])
setTimeout(() => {
setLans(["Rust", "C", "Javascript", "Typescript", "JAVA", ])
}, 1000 * 5)
return (
<ul>
<Index each={lans()}>
{
(lan, i) => (
<li>
{i}.{lan()}
</li>
)
}
</Index>
</ul>
)
}
可以发现区别就是For中,lan是一个值,而i是一个函数。Index中lan是一个函数,i是一个值。 这里的函数其实是Singal,所以说For和Index中依赖项不一样了。 如果这里使用的不是li而是input,那么使用For的话,每次修改input的value,那么都需要销毁input,重建input。改成Index就不会有这个问题,它只会更新input的value。
Portal
传送组件,主要目的提供不渲染在当前组件的父组件下的。比如自定义下拉框\选择框,如果渲染在当前组件的父组件下,有可能高度不够,不希望受到父组件的影响。又比如渲染一个弹窗,这个时候,需要讲dom挂载到body标签下的。 比如弹窗可以这么写,
import {Portal} from "solid-js/web";
function Popup() {
return (
<Portal mount={document.body}>
<div style={{
display: "flex",
"justify-content": "center",
"align-items": "center",
position: "absolute",
top: "50%",
left: "50%",
height: "50%",
width: "50%",
"background-color": "rgba(255, 255, 255, 0.5)",
transform: "translate(-50%, -50%)"
}}>
<div style={{"font-size": "30px"}}>
这是一个弹窗
</div>
</div>
</Portal>
)
}
ErrorBoundary
错误边界,这个组件是用来捕捉异常的。下面就是使用样例,可以看到,不管错误发生在组件第一次运行,还是后续渲染的过程中,都可以捕捉到。
const BrokenOnComponent = (props) => {
throw new Error("Broken On Component");
return <>Never Getting Here{throwError()}</>
}
const BrokenOnRender = (props) => {
const throwError = () => {throw new Error("Broken On Render");}
return <>Never Getting Here{throwError()}</>
}
function ErrorBoundaryExample() {
return (
<>
<div>Before</div>
<ErrorBoundary fallback={(err) => err}>
<BrokenOnComponent />
</ErrorBoundary>
<ErrorBoundary fallback={(err) => err}>
<BrokenOnRender />
</ErrorBoundary>
<div>After</div>
</>
);
}
最后
内置组件就暂时这样先吧!更加深入的理解还需要后续的学习和介绍,才可以写成文章分享给大家。