发现一个Solid中的坑

没错 solid比react对新人更加友好 不过我这种半新不新的 也更容易进入一些比较隐蔽的坑
上篇文章提到了我自制的文件路由系统 正是在写的过程中 我意识到solid没有想象中那么美好

虽然没有闭包的问题 但它有getter的问题

简单来说就是------------

你不能觉得类型没问题就真的没问题了

想要响应式 那就得传getter

以JSX对象为例 不应该const a = \<div xx/> 然后传到底下

而是要const a = ()=>\<div xx/> 然后把a传下去 给别人调用

其他类型的值其实还好 主要是JSX

它的语法比较暧昧 新手(我)很容易弄不清具体的生效时间

复盘一下

文件路由插件的原理

js 复制代码
//index.tsx
import routes from '~solid-pages'

//xxx
render(() => <Router>{routes}</Router>, root!)

vite.env.d.ts中 '~solid-pages'这个模块的默认导出是<Router>可以接受的静态配置项 所以这里没有类型错误

而实际上 vite-plugin-pages会生成一个临时的js文件 它的默认导出就是这个routes数组

我希望使用类似next.js app router的路由结构 必须重写resolver 自己实现从文件结构到js文件的全过程

最终目的是把文件结构中的layout error loading page 404转化为如下的配置项

js 复制代码
{
  path: '/',
  component: (props) => (
    <Layout>
      <ErrorBoundary
        fallback={(err, reset) => <Error err={err} reset={reset}></Error>}
      >
        <Suspense fallback={<Loading></Loading>}>{props.children}</Suspense>
      </ErrorBoundary>
    </Layout>
  ),
  children: [
    {
      path: '',
      component: Page,
    },
    //..其他的下级路由
    {
      path:'*rest',
      component: NotFound
    }
  ],
}

尝试

需要注意的是 js ts文件是不能使用jsx语法的 vite会报错

至少我反复拷打ai 没有得到解决办法

所以往'~solid-pages'里输出的其实是这种东西

js 复制代码
component:(props) =>
  createComponent(Layout, {
    children: createComponent(ErrorBoundary, {
      fallback: (err, reset) => createComponent(Error, { err, reset }),
      children: createComponent(Suspense, {
        fallback: createComponent(Loading, {}),
        children: props.children,
      }),
    }),
  })

但是发现不顶用 ErrorBoundary和Suspense都不生效 只有Layout正常

一开始我以为是这两个组件的问题 比如需要运行时什么的

想起之前看过一篇远程组件的文章 我把输出内容改成了这样

js 复制代码
export default function getRoutes(ErrorBoundary,Suspense){
    //...
}

不过还是没用

后来还试了Dynamic组件 依旧没用

解决

我又尝试改了一下写法 把组装的工作放在外面做

js 复制代码
//~solid-pages
const routesMap = {
    path:'/',
    component:{Layout,Error,Loading}
        //xxx
}
export default routesMap

// index.tsx
import routesMap from '~solid-pages'

const routes = [{
  path:'/',
  component:(props:ParentProps)=>{
    const { Layout,Error,Loading } = routesMap.xxx.xxx.xx
    let res = null
    if (Loading) {
      res = <Suspense fallback={<Loading />}>{props.children}</Suspense>
    }
    if (Error) {
      res = (
        <ErrorBoundary
          fallback={(err, reset) => <Error err={err} reset={reset} />}
        >
          {res ?? props.children}
        </ErrorBoundary>
      )
    }
    if (Layout) {
      res = <Layout>{res ?? props.children}</Layout>
    }
    return res
  }
}]

这次行了一半 能loading 不能error

把loading的部分注释掉 就可以error了

此刻我突然意识到问题的关键 那就是solid实现响应式的原理

要在使用一个值的时候调用getter函数 而不能提前把这个值取出来

所以要写成

js 复制代码
    const { Layout,Error,Loading } = routesMap.xxx.xxx.xx
    let res = null
    if (Loading) {
      res = ()=><Suspense fallback={<Loading />}>{props.children}</Suspense>
    }
    if (Error) {
      const _res = res
      res = ()=>(
        <ErrorBoundary
          fallback={(err, reset) => <Error err={err} reset={reset} />}
        >
          {_res?_res(): props.children}
        </ErrorBoundary>
      )
    }
    if (Layout) {
      const _res = res
      res = ()=> <Layout>{_res ?_res(): props.children}</Layout>
    }
    return res()

其实刚才的写法 Layout的children也不会自动更新 但一开始我以为是热更新的问题 并没有发现

那么为什么一开始的createComponent也不行呢?

js 复制代码
      createComponent(Suspense, {
        fallback: createComponent(Loading, {}),
        children: props.children,
      })

原因是这里已经把props.children的值取了

正确的写法是

js 复制代码
      createComponent(Suspense, {
        fallback: createComponent(Loading, {}),
        get children(){ 
          return props.children 
        },
      })

此事(get children())在文档里亦有记载 不过当时我不知道为什么要这么写 现在又找不到具体位置了

所以这种写法是错误的

js 复制代码
const comp = <div xx/>

return <div>{comp}</div>

要写成

js 复制代码
const comp = ()=><div xx/>
或者
const comp = children(()=><div xxx/>)

return <div>{comp}</div>

其实换成数字或者随便一个其他类型 都不会出错 主要是JSX语法和react太像 太具有迷惑性了

更新

还是存在问题 但是我已经不知道原因了 热更新就是不行 ErrorBoundary 就是拦截不到异常

what can i say 摆了

还有一个问题

'/test1'切换回'/' 居然不能触发loading?

这下有正当理由切回next了

相关推荐
广州华水科技3 分钟前
北斗形变监测传感器在大坝安全监测中的应用与优势分析
前端
孔令飞10 分钟前
如何学习Go
前端
HUIBUR科技14 分钟前
AI 中枢,面向企业场景构建的 AI 智能体
前端·数据库·人工智能
怕浪猫21 分钟前
给AI配一台电脑,开源版Muse来了,OpenMuse赶紧去二次开发吧
javascript·面试·github
随便写个软件31 分钟前
【新版本】EasyExplorer资源管理器 3.12.0——地址栏重要更新
运维·服务器·前端·everything·资源管理器
Jack N34 分钟前
【Strapi 系列之二】Collection / Single / Component 怎么选?Strapi 字段大全一篇讲透
前端·javascript·strapi
hiahiahia12342 分钟前
Agent Tool 执行失败怎么办
服务器·前端
Java后端的Ai之路42 分钟前
09-React组件生命周期
前端·react.js·前端框架
IT_陈寒1 小时前
SpringBoot开发实战:从入门到精通
前端·人工智能·后端
乘风gg1 小时前
一个人一个月合并 2500 PRs 的秘密是什么?
前端·ai编程·claude