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和开发第三方库有关 可以自行翻阅文档

第三方库

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

相关推荐
spionbo2 分钟前
前端解构赋值避坑指南基础到高阶深度解析技巧
前端
用户4099322502126 分钟前
Vue响应式声明的API差异、底层原理与常见陷阱你都搞懂了吗
前端·ai编程·trae
开发者小天8 分钟前
React中的componentWillUnmount 使用
前端·javascript·vue.js·react.js
永远的个初学者42 分钟前
图片优化 上传图片压缩 npm包支持vue(react)框架开源插件 支持在线与本地
前端·vue.js·react.js
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ43 分钟前
npm i / npm install 卡死不动解决方法
前端·npm·node.js
Kratzdisteln1 小时前
【Cursor _RubicsCube Diary 1】Node.js;npm;Vite
前端·npm·node.js
杰克尼1 小时前
vue_day04
前端·javascript·vue.js
明远湖之鱼2 小时前
浅入理解跨端渲染:从零实现 React DSL 跨端渲染机制
前端·react native·react.js
悟忧2 小时前
规避ProseMirror React渲染差异带来的BUG
前端
小皮虾2 小时前
小程序云开发有类似 uniCloud 云对象的方案吗?有的兄弟,有的!
前端·javascript·小程序·云开发