solid: react导演剪辑终极扑街版

写在最后

为啥是写在最后呢?因为这段话是文章写完才打的 标题里的扑街也是写完才加的

原因是solid的路由库非常垃圾 既不支持<RouteView>嵌套路由 也不能接受剩余的路径参数

这下算白忙活了 我自己做小项目也不会用这种东西的 我真傻 真的

solid优点是有的 而且非常明显 不过就是典型的一问都在夸 二问没人用

一句话solid

js 复制代码
const App: Component = () => {
  const [count, setCount] = createSignal(0);
  const increment = () => setCount(count() + 1);
  return (
    <button onClick={increment}>{count()}</button>
    );
};

等价于

js 复制代码
class App extends Component {
  constructor() {
    super();
    this.state = {
      count: 0
    };
  }
  increment() {
    this.setState({ count: this.state.count + 1 });
  };
  render() {
    return (
      <button onClick={()=>this.increment()}>{this.state.count}</button>
    );
  }
}

感动吗?solid甚至不需要eslint

solid在保持了简洁的同时 规避了函数组件最大的缺点

solid的state是一个getter函数->组件函数只需要被调用一次->不必担心闭包问题->不需要反复理解此state为什么不是彼state

重要api

createEffect

基本用法

和useEffect很类似 但会自动收集依赖

在组件创建和渲染完毕后,调用一次effect函数,无论组件函数中是否变更过signal

之后每当依赖变更 调用effect函数

scss 复制代码
  createEffect(() => {
    console.log(count());
  });

如果想从上一次effect中得到一些信息

effect函数可以拥有一个参数

第一次调用时,effect函数会接受createEffect的参数2作为参数(也可以不写 那样的话就是undefined)

后续的每次调用 都会以effect函数的返回值作为参数

js 复制代码
  createEffect((flag: boolean) => {
    if (flag) {
      return
    }
    console.log(count())
    return count() > 5;
  }, false);

也可以用于保存prevValue

js 复制代码
  createEffect((prevValue?: number) => {
    console.log('prev:' + prevValue)
    return count()
  });

以上情况对于数组均适用

说明

  • effect函数的参数类型必须显式写出来 不能通过其返回值和初始值的类型得出 这与typescript的机制有关系 参考这篇文章
  • 依赖收集仅限同步部分 如果有回调函数、promise、setTimeout中执行的代码 这样做
js 复制代码
  createEffect(() => {
    const value = count();
    setTimeout(() => console.log(value), 0);
  });
  • 不要把effect函数设置为异步函数
  • 不用担心if for等语句影响依赖收集
  • 不建议用这个函数获取数据 参考后文createResource

on

手动控制createEffect的依赖项 类似于vue里的watch
createEffect(on(deps,fn,{ defer?: boolean}))

defer

defer为true则不执行第一次

deps

scss 复制代码
const [a] = createSigal(0)
const b = createMemo(()=>a()*2)
const c = ()=>a()*2
const d = ()=> ({ a:a:(), d:1 })

const deps = a
// const deps = [b,c]
// const deps = ()=>d().d

createEffect(on(deps,fn))

注意 d().d虽然不变 但是依旧会触发fn 需要这样写

scss 复制代码
const e = createMemo(()=>d().d)

fn

函数签名

php 复制代码
fn: (input: T, prevInput: T, prevValue?: U) => U

input 这次的deps

prevInput 上次的deps

prevValue createEffect的初始值 或者上次调用fn的返回值

onMount

scss 复制代码
onMount(fn)

挂载后调用一次fn 只执行一次的effect

不建议用这个函数获取数据 参考后文createResource

onCleanup

在effect中调用onCleanup 清理函数会在下次effect之前被调用

js 复制代码
createEffect(()=>{
    onCleanup(xxx)
})

直接写在组件函数中则是卸载时调用

js 复制代码
onCleanup(xxx)

createMemo

基本用法

类似于useMemo 依赖收集、同步异步、清理函数等和createEffect相同

js 复制代码
const doubleValue = createMemo(() => count() * 2);

<button>{doubleValue()}<button>

与createEffect类似 memo函数也可以接受一个参数

第一次调用时 这个参数是createMemo的参数2 后续则是上次memo函数调用的返回值

如果不需要memo

js 复制代码
// 正确
const doubleValue = () => count() * 2;

<button>{doubleValue()}<button>

// 错误
const doubleValue = count() * 2;

<button>{doubleValue}<button>

说明

  • createMemo和useMemo作用相同 可以缓存复杂计算的结果
  • createMemo可以获取上次计算的结果
  • createMemo可以接受一个自定义的equals函数
js 复制代码
createMemo(xxx,xxx,{ equals: Object.is })

createResource

基本用法

类似于useActionState 管理异步状态

这个函数比较复杂 建议参考文档 这里只做简单介绍

js 复制代码
const [data, { mutate, refetch }] = createResource(fetchData)

参数和返回值

fetchData
  • 数据获取函数 不会自动收集其中的依赖
  • 可以是异步的
  • 组件创建时会被立刻调用
  • 不会出现先发后至的问题 之前一次发起的请求比后一次晚结束 data也会取后一次请求的值 因此不需要管理队列
data

data() 从fetchData里获取的数据
data.loading
data.error
data.latestfetchData返回的最新值
data.state 值为"unresolved" | "pending" | "ready" | "refreshing" | "errored" 比loading和error更详细 以上都是singal

mutate

强制将data置为某个值

refetch

重新获取data

fetchData相关

createResource也可以写做createResource(source,fetchData)

source可以是一个普通值 也可以是一个getter函数

如果source(或者其返回值)是false、null、undefined则fetchDate总是不会被调用

如果source是getter函数 且它的返回值不是上述空值且发生了变化 则fetchData被自动调用

fetchData接受这样的参数

js 复制代码
fetchData(source,info:{ value, refetching })

如果没有source 则fetchData的参数1是true

createContext

基本用法

和React.createContext差不多

ini 复制代码
const ValueContext = createContext<number>() // 可以传一个defaultValue

// 直接传递一个值
const num = 1
<ValueContext.Provider value={num}>xxx</ValueContext.Provider>

// 如果想让子组件取得信号 应该直接把getter传下去
const [count] = createSignal(0)
<ValueContext.Provider value={count}>xxx</ValueContext.Provider>

const num = 1
<ValueContext.Provider value={num}>xxx</ValueContext.Provider>

// 获取传下来的值
useContext(ValueContext)

说明

文档建议

ref

基本用法

获取dom的引用

js 复制代码
let dom
<div ref={dom} />

let comp
<Comp ref={comp}/>
const Comp = props=>{
    return <div ref={props.ref}/>
}

获取组件的引用

不存在"组件的引用" 需要从子组件中获取什么 直接这样写就可以了

javascript 复制代码
let someValue

<Comp setter={val=>someValue=val} />

const Comp = props=>{
    props.setter(1)
    return <div/>
}

样式

class

solid中没有className 而是使用class

style

style可以是字符串或对象 但不支持驼峰写法

js 复制代码
// 错误
style={{ backgroundColor: 'red' }}
// 正确
style={{ 'background-color': 'red' }}

因为底层是style.setProperty

ParentComponent

等效于FC<PropsWithChildren> 在props添加children属性

不重要的api

children

js 复制代码
import { children } from 'solid-js'

const resolved = children(()=>props.children)

作用是惰性加载children(比如条件渲染 不一定用得到) 还会对做一些jsx专属的操作

不一定是children属性 只要是一个返回jsx的getter函数都可以

createStore

对象或数组的signal 感觉不如immer

createUniqueId

约等于useId

ini 复制代码
const id = createUniqueId()

id是string 不是getter 直接用

on:*

这种事件会被直接放在dom上而不被委托

js 复制代码
<div on:DOMContentLoaded={(e) => console.log("Welcome!")} />

untrack

在这个函数里面所读取的signal不会被收集为依赖

<Suspense>

和react类似 但仅由createResource触发

js 复制代码
const MyComponentWithSuspense = () => {
  const [data] = createResource(async () => {xxx})
  return (
    <Suspense fallback={xxx}>
        {data()}
    </Suspense>
  )
}

其他

<ErrorBoundary> lazy懒加载 等和react类似
For.map Showa?b:c等据说有优化 但不是特别必要

还有一些底层api 与ssr和开发第三方库有关 可以自行翻阅文档

第三方库

内容比较多 可以去我的模板里看

相关推荐
木木黄木木26 分钟前
css炫酷的3D水波纹文字效果实现详解
前端·css·3d
郁大锤1 小时前
Flask与 FastAPI 对比:哪个更适合你的 Web 开发?
前端·flask·fastapi
HelloRevit2 小时前
React DndKit 实现类似slack 类别、频道拖动调整位置功能
前端·javascript·react.js
ohMyGod_1232 小时前
用React实现一个秒杀倒计时组件
前端·javascript·react.js
eternal__day2 小时前
第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)
java·前端·spring·java-ee·mvc
醋醋2 小时前
Vue2源码记录
前端·vue.js
江耳3 小时前
从10秒到无限流:我用Vercel+NextJS实现AI流式对话遇到的超时问题及解决方案
前端
总之就是非常可爱3 小时前
三分钟让你看懂alien-signals computed基本原理
前端
JustHappy3 小时前
「我们一起做组件库🌻」虚拟消息队列?message组件有何不同?(VersakitUI开发实录)
前端·javascript·vue.js
Carlos_sam3 小时前
Openlayers:为Overlay创建element的四种方式
前端·javascript·vue.js