发现一个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了

相关推荐
吴永琦(桂林电子科技大学)16 分钟前
HTML5
前端·html·html5
爱因斯坦乐18 分钟前
【HTML】纯前端网页小游戏-戳破彩泡
前端·javascript·html
恋猫de小郭24 分钟前
注意,暂时不要升级 MacOS ,Flutter/RN 等构建 ipa 可能会因 「ITMS-90048」This bundle is invalid 被拒绝
android·前端·flutter
还是鼠鼠1 小时前
Node.js自定义中间件
javascript·vscode·中间件·node.js·json·express
前端极客探险家3 小时前
Flutter vs React Native:跨平台移动开发框架对比
flutter·react native·react.js
大莲芒4 小时前
react 15-16-17-18各版本的核心区别、底层原理及演进逻辑的深度解析--react17
前端·react.js·前端框架
木木黄木木6 小时前
html5炫酷3D文字效果项目开发实践
前端·3d·html5
Li_Ning217 小时前
【接口重复请求】axios通过AbortController解决页面切换过快,接口重复请求问题
前端
胡八一7 小时前
Window调试 ios 的 Safari 浏览器
前端·ios·safari
Dontla7 小时前
前端页面鼠标移动监控(鼠标运动、鼠标监控)鼠标节流处理、throttle、限制触发频率(setTimeout、clearInterval)
前端·javascript