学习《SolidJS》(三)自定义组件

Props

本文章中所有的编译结果都只是假想的,只是逻辑上的,不代表真实的编译结果

定义与传递

tsx 复制代码
function ChildComponent(props: {label: string, value: string}){
  return (
    <div>{props.label}:{props.value}</div>
  )
}

function ParentComponent(){
  return (
    <div>
      <h3>用户信息</h3>
      <ChildComponent label="用户名" value="张三"/>
      <ChildComponent label="年龄" value="22"/>
      <ChildComponent label="性别" value="男"/>
    </div>
  )
}

属性的定义和传递就是如上面代码这样写就行。如果你用的是jsx,那子组件中props的定义必定是不用写的。

Props的响应式

把ParentComponent中的value修改为响应式数据,如下

tsx 复制代码
import {createSignal} from "solid-js";

function ParentComponent(){
  const [username, setUsername] = createSignal("张三");

  setTimeout(() => {
    setUsername("李四")
  }, 1000 * 3);

  return (
    <div>
      <h3>用户信息</h3>
      <ChildComponent label="用户名" value={username()}/>
      <ChildComponent label="年龄" value="22"/>
      <ChildComponent label="性别" value="男"/>
    </div>
  )
}

上面这样写了之后,会发现经过3s后,用户名确实是从张三变成了李四。不过这里有个地方要注意的,那就是有些开发者可能会习惯性的在子组件中使用解构,就像下面这样写

tsx 复制代码
function ChildComponent(props: {label: string, value: string}){
  const {label, value} = props;

  return (
    <div>{label}:{value}</div>
  )
}

使用这种写法,会发现经过了3s后,用户名仍然是张三。也就是解构之后再使用就不是响应式数据了,所以各位不要随意的解构。这是因为,props中的属性其实有可能是一个getter。就下下面这样的,

ts 复制代码
{
    label: "用户名",  //因为这个是字面量,不需要响应式,所以不需要做成getter
    get value() {
        return username();
    }
}

这里其实就会发现,value这个getter函数,其实就是衍生Signal,直接与上一篇文章说的对应上了。 当我们解构props的时候就相当于,就相当于创建组件时调用了这个衍生Signal,所以失去了响应式的效果

tsx 复制代码
function ChildComponent(props: {label: string, value: string}){
  const label = props.label;
  const value = props.value;

  return (
    <div>{label}:{value}</div>
  )
}

分离Props

在上面的子组件中,我们使用的就是div,有些时候我们希望子组件可以接收所有的div属性,然后除了label和value,把其它的都原样传递给,在React中我们可能使用解构的写法,如下

tsx 复制代码
import {  HTMLAttributes } from 'react'

function ChildComponent(props: {label: string, value: string} & HTMLAttributes<HTMLDivElement>){
  const {label, value, ...other} = props;

  return (
    <div {...other}>{label}:{value}</div>
  )
}

但是刚刚说过了,SolidJS不能这样解构,所以SolidJS通过了一个函数让我面来分离Props,所以就写出下面这样

tsx 复制代码
import {JSX, splitProps} from "solid-js";

function ChildComponent(props: {label: string, value: string} & JSX.HTMLAttributes<HTMLDivElement>){
  const [local, other] = splitProps(props, ["label", "value"]);

  return (
    <div {...other}>{local.label}:{local.value}</div>
  )
}

基本用法就是,第一个参数传递的是要切分的props,固定这么写就行;第二个参数是一个数组,写的是要切分的属性名称。这样切分之后,local包含了数组中指明的属性,other就是剩下的。

默认Props

在开发过程中,我们写的组件经常会有默认值,也就是有很多属性我们可以不用填,假设上面的子组件value如果不填默认是"-",我们同样需要用到SolidJS提供函数mergeProps实现。修改后如下代码:

tsx 复制代码
import {JSX, splitProps, mergeProps} from "solid-js";

function ChildComponent(props: {label: string, value?: string} & JSX.HTMLAttributes<HTMLDivElement>){
  props = mergeProps({value: "-"}, props);
  const [local, other] = splitProps(props, ["label", "value"]);

  return (
    <div {...other}>{local.label}:{local.value}</div>
  )
}

生命周期

在开发过程中,其实经常会需要在组件挂载或者卸载时执行一些代码,所以SolidJS提供了对应生命周期。 两个函数分别是onMount和onCleanup。比如说,现在我需要监听窗口宽度的变化,然后改变我的界面。 这个时候就需要在挂载的时候,添加监听reszie事件,在卸载的时候取消监听。

tsx 复制代码
import {Accessor, createSignal, onCleanup, onMount} from "solid-js";

export function useInnerWidth(): Accessor<number> {
  const [innerWidth, setInnerWidth] = createSignal(window.innerWidth)

  const onResize = () => {
    setInnerWidth(window.innerWidth)
  }
  onMount(() => window.addEventListener("resize", onResize))
  onCleanup(() => window.removeEventListener("resize", onResize))

  return innerWidth
}

上面这个代码就是创建了一个Signal,然后添加了监听事件。使用它也是非常的简单的,

tsx 复制代码
function CurrentInnerWidth(){
  const innerWidth = useInnerWidth();
  
  return(
    <h3>当前窗口宽度:{innerWidth()}px</h3>
  )
}

一些需要请求后端数据的,也可以使用类似useInnerWidth函数的的写法,只是不需要onCleanup,不过这里我就不给大家演示。

最后

今天就先写到这里了,对于自定义组件来说,props是经常用到的。props是存在一点问题的,特别是一定一定要注意不要随意解构,要使用SolidJS提供的函数来实现。

相关推荐
野槐2 分钟前
前端图像处理(一)
前端
程序猿阿伟9 分钟前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒11 分钟前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪19 分钟前
AJAX的基本使用
前端·javascript·ajax
力透键背22 分钟前
display: none和visibility: hidden的区别
开发语言·前端·javascript
程楠楠&M33 分钟前
node.js第三方Express 框架
前端·javascript·node.js·express
盛夏绽放41 分钟前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
想自律的露西西★1 小时前
用el-scrollbar实现滚动条,拖动滚动条可以滚动,但是通过鼠标滑轮却无效
前端·javascript·css·vue.js·elementui·前端框架·html5
白墨阳1 小时前
vue3:瀑布流
前端·javascript·vue.js
霍先生的虚拟宇宙网络2 小时前
webp 网页如何录屏?
开发语言·前端·javascript