npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-solidlike

v2.5.4

Published

Declarative React control flow components inspired by Solid.js, replacing ternary expressions and array.map() in JSX

Readme

react-solidlike

English | 中文

声明式 React 控制流组件库,灵感来源于 Solid.js。用于替代 JSX 中的三元表达式和 array.map(),让你的组件代码更加清晰易读。支持 React 和 React Native。

安装

npm install react-solidlike
# 或
bun add react-solidlike

组件

<Show> - 条件渲染

替代三元表达式进行条件渲染。

import { Show } from "react-solidlike";

// 基础用法
<Show when={isLoggedIn}>
  <UserProfile />
</Show>

// 带 fallback
<Show when={isLoggedIn} fallback={<LoginButton />}>
  <UserProfile />
</Show>

// 使用 render props 获取类型安全的值
<Show when={user}>
  {(user) => <UserProfile name={user.name} />}
</Show>

// 带 onFallback 回调(用于重定向等副作用)
<Show when={isAuthenticated} fallback={<Loading />} onFallback={() => navigate('/login')}>
  <Dashboard />
</Show>

<For> - 列表渲染

替代 array.map() 进行列表渲染。

import { For } from "react-solidlike";

// 基础用法
<For each={items}>
  {(item) => <ListItem {...item} />}
</For>

// 带 keyExtractor
<For each={users} keyExtractor={(user) => user.id}>
  {(user) => <UserCard user={user} />}
</For>

// 带 fallback 处理空数组
<For each={items} fallback={<EmptyState />}>
  {(item, index) => <ListItem item={item} index={index} />}
</For>

// 使用 wrapper 包装元素
<For each={items} wrapper={<ul className="list" />}>
  {(item) => <li>{item.name}</li>}
</For>

// 倒序渲染
<For each={messages} reverse>
  {(msg) => <Message {...msg} />}
</For>

// 使用 array 参数获取上下文信息
<For each={steps}>
  {(step, index, array) => (
    <Step
      data={step}
      isFirst={index === 0}
      isLast={index === array.length - 1}
    />
  )}
</For>

<Switch> / <Match> / <Default> - 多分支渲染

替代多个 if-elseswitch 语句。

import { Switch, Match, Default } from "react-solidlike";

<Switch>
  <Match when={status === "loading"}>
    <LoadingSpinner />
  </Match>
  <Match when={status === "error"}>
    <ErrorMessage />
  </Match>
  <Match when={status === "success"}>
    <SuccessContent />
  </Match>
  <Default>
    <IdleState />
  </Default>
</Switch>

<Await> - 异步等待

等待 Promise resolve 后渲染内容。

import { Await } from "react-solidlike";

// 基础用法
<Await promise={fetchUser()} loading={<Spinner />}>
  {(user) => <UserProfile user={user} />}
</Await>

// 带错误处理
<Await
  promise={fetchData()}
  loading={<Loading />}
  error={(err) => <ErrorMessage message={err.message} />}
>
  {(data) => <DataView data={data} />}
</Await>

// 支持非 Promise 值(用于缓存场景)
<Await promise={cache ?? fetchData()} loading={<Spinner />}>
  {(data) => <DataView data={data} />}
</Await>

<Repeat> - 重复渲染

替代 Array.from({ length: n }).map()

import { Repeat } from "react-solidlike";

// 渲染星级评分
<Repeat times={5}>
  {(i) => <Star key={i} filled={i < rating} />}
</Repeat>

// 生成骨架屏占位
<Repeat times={3}>
  {(i) => <SkeletonCard key={i} />}
</Repeat>

// 使用 wrapper 包装元素
<Repeat times={5} wrapper={<div className="stars" />}>
  {(i) => <Star key={i} />}
</Repeat>

// 倒序渲染
<Repeat times={5} reverse>
  {(i) => <div key={i}>倒序 {i}</div>}
</Repeat>

// 使用 length 参数显示进度
<Repeat times={totalSteps}>
  {(i, length) => (
    <Step key={i} current={i + 1} total={length} />
  )}
</Repeat>

<Split> - 字符串切割渲染

按分隔符切割字符串并渲染每个部分。

import { Split } from "react-solidlike";

// 基础用法 - 切割后不保留分隔符
<Split string="a,b,c" separator=",">
  {(part) => <span>{part}</span>}
</Split>
// 渲染: ["a", "b", "c"]

// 保留分隔符
<Split string="9+5=(9+1)+4" separator="=" keepSeparator>
  {(part) => <span>{part}</span>}
</Split>
// 渲染: ["9+5", "=", "(9+1)+4"]

// 使用正则表达式分隔符
<Split string="a1b2c3" separator={/\d/} keepSeparator>
  {(part) => <span>{part}</span>}
</Split>
// 渲染: ["a", "1", "b", "2", "c", "3"]

// 带 wrapper 包装元素
<Split string="hello world" separator=" " wrapper={<div className="words" />}>
  {(word) => <span>{word}</span>}
</Split>

// 带 fallback 处理空字符串
<Split string={text} separator="," fallback={<EmptyState />}>
  {(part) => <Tag>{part}</Tag>}
</Split>

// 倒序渲染
<Split string="a,b,c" separator="," reverse>
  {(part) => <span>{part}</span>}
</Split>
// 渲染顺序: ["c", "b", "a"]

<Dynamic> - 动态组件

根据条件动态选择要渲染的组件类型。

import { Dynamic } from "react-solidlike";

// 动态选择按钮或链接
<Dynamic
  component={href ? 'a' : 'button'}
  href={href}
  onClick={onClick}
>
  {label}
</Dynamic>

// 配合自定义组件
<Dynamic
  component={isAdmin ? AdminPanel : UserPanel}
  user={currentUser}
/>

// React Native 中使用
<Dynamic
  component={isPressable ? Pressable : View}
  onPress={handlePress}
>
  <Text>Content</Text>
</Dynamic>

<ErrorBoundary> - 错误边界

捕获子组件树中的 JavaScript 错误,防止整个应用崩溃。

import { ErrorBoundary } from "react-solidlike";

// 基础用法
<ErrorBoundary fallback={<ErrorPage />}>
  <App />
</ErrorBoundary>

// 使用 render props 获取错误信息和重置函数
<ErrorBoundary
  fallback={(error, reset) => (
    <div>
      <p>Error: {error.message}</p>
      <button onClick={reset}>Retry</button>
    </div>
  )}
>
  <App />
</ErrorBoundary>

// resetKey 变化时自动重置
<ErrorBoundary fallback={<Error />} resetKey={userId}>
  <UserProfile />
</ErrorBoundary>

<QueryBoundary> - 查询边界

处理异步查询的各种状态(加载中、错误、空数据、成功)。可与 @tanstack/react-query、SWR、RTK Query 等配合使用。

import { QueryBoundary } from "react-solidlike";
import { useQuery } from "@tanstack/react-query";

function UserList() {
  const query = useQuery({ queryKey: ["users"], queryFn: fetchUsers });

  return (
    <QueryBoundary
      query={query}
      loading={<Spinner />}
      error={<ErrorMessage />}
      empty={<NoData />}
    >
      {(users) => (
        <ul>
          {users.map((user) => (
            <li key={user.id}>{user.name}</li>
          ))}
        </ul>
      )}
    </QueryBoundary>
  );
}

Props

| 属性 | 类型 | 描述 | | ----------- | ------------------------------------- | ------------ | | query | QueryResult<T> | 查询结果对象 | | loading | ReactNode | 加载中显示 | | error | ReactNode | 错误时显示 | | empty | ReactNode | 空数据显示 | | children | ReactNode \| (data: T) => ReactNode | 成功时渲染 | | isEmptyFn | (data: T) => boolean | 自定义空判断 |

<Once> - 单次渲染

只渲染一次子元素,忽略后续更新。适用于昂贵的计算或不应重新渲染的内容。

import { Once } from "react-solidlike";

// 渲染昂贵的组件
<Once>
  <ExpensiveChart data={data} />
</Once>

// 防止父组件更新导致的重新渲染
function Parent() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
      <Once>
        <Child initialCount={count} />
      </Once>
    </div>
  );
}

<ClientOnly> - 仅客户端渲染

仅在客户端(hydration 之后)渲染子元素。适用于依赖浏览器 API 或需要避免 SSR hydration 不匹配的场景。

import { ClientOnly } from "react-solidlike";

// 基础用法
<ClientOnly>
  <BrowserOnlyComponent />
</ClientOnly>

// 带 SSR 备选内容
<ClientOnly fallback={<Skeleton />}>
  <DynamicChart />
</ClientOnly>

// 使用渲染函数延迟求值(避免访问 window)
<ClientOnly fallback={<Loading />}>
  {() => <ComponentUsingWindow width={window.innerWidth} />}
</ClientOnly>

// 避免 hydration 不匹配
<ClientOnly fallback={<span>--:--</span>}>
  <CurrentTime />
</ClientOnly>

<Timeout> - 超时渲染

在指定延迟后显示或隐藏内容。适用于自动消失的通知、延迟加载的场景。

import { Timeout } from "react-solidlike";

// 延迟后显示(mode="after",默认)
<Timeout ms={1000} mode="after" fallback={<Spinner />}>
  <DelayedContent />
</Timeout>

// 延迟后隐藏(mode="before")
<Timeout ms={3000} mode="before">
  <Toast message="操作成功!" />
</Timeout>

// 自动消失的提示
<Timeout ms={5000} mode="before" onTimeout={() => console.log("已消失")}>
  <Notification type="success">保存成功</Notification>
</Timeout>

// 带加载状态的延迟渲染
<Timeout ms={2000} mode="after" fallback={<Skeleton />}>
  <ExpensiveComponent />
</Timeout>

Props

| 属性 | 类型 | 描述 | | ----------- | --------------------- | --------------------------------------------------------------- | | ms | number | 延迟时间(毫秒) | | mode | 'after' \| 'before' | 'after' = 延迟后显示,'before' = 延迟后隐藏,默认 'after' | | children | ReactNode | 要渲染的内容 | | fallback | ReactNode | 等待时显示的内容(仅 after 模式) | | onTimeout | () => void | 超时发生时的回调 |

<Visible> - 可见性渲染(仅 Web)

基于 IntersectionObserver 的可见性渲染,进入视口才渲���。在 React Native 或不支持的环境中会直接渲染 children(优雅降级)。

import { Visible } from "react-solidlike";

// 基础用法 - 进入视口时渲染
<Visible>
  <HeavyComponent />
</Visible>

// 带占位符
<Visible fallback={<Skeleton />}>
  <Image src={url} />
</Visible>

// 提前预加载(rootMargin)
<Visible rootMargin="200px" fallback={<Placeholder />}>
  <LazyImage />
</Visible>

// 切换可见性(once=false 时离开视口会卸载)
<Visible once={false} onVisibilityChange={(v) => console.log(v)}>
  <VideoPlayer />
</Visible>

开发

# 安装依赖
bun install

# 运行测试
bun test

# 代码检查
bun run lint

# 构建
bun run build

License

MIT