solidjs API使用

createSignal

当改变值要重新渲染界面,可以使用 createSignal API;

当点击的时候调用 setA 函数改变 a 的值,界面上也会更新。

import { createSignal } from "solid-js";

 const test1 = () => {
  const [a, setA] = createSignal(1);
  
  const handleClick = (data)=>{
    setA(data)
  }

  const handleClick2 = ()=>{
    setA(a()+1)
  }

  // 只执行一遍
  console.log(0,'render')
  
  return (
    <div>
      <xy-button onClick={() => handleClick(a() + 1)}>{a()}</xy-button>
      <xy-button onClick={() => handleClick2()}>{a()}</xy-button>
      {/* onClick 的内容不会随之按钮的点击而变化,所以连续点击不会连续增加 */}
      <xy-button onClick={[handleClick,a()+1]}>{ a() }</xy-button>
    </div>
  );
};

可以设置第二个参数;

当设置 { equals: false } 时,就会强制更新。
每次点击按钮 调用 setA 时会被 createEffect 监听到依赖项变化,每次都打印 1, 监听a的值:a =xxx

equals 值可以是false,一个返回布尔值的函数,如 (newVal, oldVal) => newVal.length === oldVal.length。当长度不相等返回 false 响应更新。

const test2 = () => {
  const [a, setA] = createSignal(1, { equals: false });

  createEffect(() => console.log(1, "监听a的值:a =", a()));

  const handleClick = () => {
    setA(a());
  };

  // 只执行一遍
  console.log(0, "render");

  return (
    <div>
      <xy-button onClick={() => handleClick()}>{a()}</xy-button>
    </div>
  );
};

监听对象


const test3 = () => {
  const [a, setA] = createSignal({ b: 1 });

  createEffect(() => console.log(1, "监听a的值:a =", a()));

  const handleClick = () => {
    setA({ b: a().b + 1 });
  };

  // 只执行一遍
  console.log(0, "render");

  return (
    <div>
      <xy-button onClick={() => handleClick()}>{a().b}</xy-button>
    </div>
  );
};

设置为一个函数

const test4 = () => {
  const [a, setA] = createSignal({ b: 1 });

  createEffect(() => console.log(1, "监听a的值:a =", a()));

  const handleClick = () => {
    setA((current)=>{
      current.b+=1;
      // 直接返回 current 会判断是一个值,不会响应依赖更新,因为 current 是引用类型
      // 可以返回一个新对象,或者 设置{ equals: false }
      // return current
      return {...current}
    });
  };

  // 只执行一遍
  console.log(0, "render");

  return (
    <div>
      <xy-button onClick={() => handleClick()}>{a().b}</xy-button>
    </div>
  );
};

createEffect

在依赖项发生变化时运行的方法

import { createSignal, createEffect } from "solid-js";


const test1 = () => {
  const [a, setA] = createSignal(2);

  createEffect(() => console.log(1, "监听a的值:a =", a()));

  const handleClick = () => {
    setA(a()+1);
  };

  // 只执行一遍
  console.log(0, "render");

  return (
    <div>
      <xy-button onClick={() => handleClick()}>{a()}</xy-button>
    </div>
  );
};




export default test1;

除了回调函数可以传一个参数

// 俩兔子,兔子寿命1年,生一窝11个,不考虑人类社会道德因素,计算 a 年有多少兔子
const test2 = () => {
  const [a, setA] = createSignal(1);

  createEffect(([preSum,dieNum]) => {
    var newBorn = Math.floor(preSum/2)*11
    const currentSum = preSum + newBorn - dieNum;
    console.log(1`${a()}年数量:${currentSum},前一年数量:${preSum},今年新生:${newBorn},今年死亡:${dieNum}`)
    return [currentSum,preSum];
  }, [2,0]);

  const handleClick = () => {
    setA(a()+1);
  };

  // 只执行一遍
  console.log(0, "render");

  return (
    <div>
      <xy-button onClick={() => handleClick()}>{a()}</xy-button>
    </div>
  );
};

如果要等待createEffect里的回调函数第一次执行发生一些什么,最简单的是用 setTimeout ,还有 Promise,queueMicrotask


const test3 = () => {
   // 0 'render'
    // 1 'a= ' 1
    // 2 'Promise'
    // 3 'microtask'
    // 2 'a= ' 3
    // 4 'goodbye'
  const [a, setA] = createSignal(1);

  
  Promise.resolve(null).then(()=>{
    console.log(2,'Promise')
  })
  self.queueMicrotask(() => {
    // 现在将打印 `a = 1` 
    console.log(3,"microtask");
    setA(3); // 立即打印 `a = 3`
    console.log(4,"goodbye");
  });
  createEffect(() => {
    console.log(1,"a= ",a())
  });


  const handleClick = () => {
    setA(a()+1);
  };

  // 只执行一遍
  console.log(0, "render");

  return (
    <div>
      <xy-button onClick={() => handleClick()}>{a()}</xy-button>
    </div>
  );
};

清空副作用中定义的定时器


const test4 = () => {
  const [a, setA] = createSignal(1);

  createEffect(() => {
    var t = setInterval(() => {
      console.log("setInterval");
    }, 800);
    //  onCleanup 是 SolidJS 中的一个钩子函数,它在组件卸载(unmount)之前调用。它常用来进行清理和收尾工作,例如释放资源、取消定时器、删除事件监听等等。
    onCleanup(() => {
      window.clearInterval(t);
    });
  });

  const handleClick = () => {
    setA(a() + 1);
  };

  // 只执行一遍
  console.log(0, "render");

  return (
    <div>
      <xy-button onClick={() => handleClick()}>{a()}</xy-button>
    </div>
  );
};

createEffect

依赖变化时计算并返回,相当于vue中的computed,如果square的那个函数不用createMemo包裹就会每次都能检测square是变化的,用了createMemo只有当返回值不一样createEffect才检测到,这和vue中用computed和用method的区别一样的。

memo 函数不应该通过调用 setter 来改变其他 signal(它应该是“纯的”)。这使得 Solid 能够根据其依赖关系图优化 memo 更新的执行顺序,以便所有 memo 最多可以更新一次以响应依赖关系的变化。

import { createSignal, createEffect, createMemo } from "solid-js";

const test1 = () => {
  const [a, setA] = createSignal(2);

  const square = createMemo(() => {
    return a()*a()
  });

  createEffect(() => console.log(1, "监听square的值:square =", square()));

  const handleClick = () => {
    setA(a() + 1);
  };

  // 只执行一遍
  console.log(0, "render");

  return (
    <div>
      <xy-button onClick={() => handleClick()}>{square}</xy-button>
    </div>
  );
};

export default test1;

接受初始值和上一次的值

// 计算等差数列之和
const test2 = () => {
  const [a, setA] = createSignal(1);

  const s = createMemo((pre) => {
    return  pre+a()
  },0);


  const handleClick = () => {
    setA(a() + 1);
  };

  // 只执行一遍
  console.log(0, "render");

  return (
    <div>
      <xy-button onClick={() => handleClick()}>{s}</xy-button>
    </div>
  );
};

可以传第三个参数,它的结构是这样的,意思和createSignal的意思差不多。

options?: { equals?: false | ((prev: T, next: T) => boolean) }

createResource

用于触发请求,两种用法

const [data, { mutate, refetch }] = createResource(fetchData);
const [data, { mutate, refetch }] = createResource(sourceSignal, fetchData);
import {
  createSignal,
  createEffect,
  createMemo,
  createResource,
} from "solid-js";

// 对象转为查询字符串
const obj2queryStr = (obj = {}) => {
  var str = "";
  for (const k in obj) {
    if (Object.hasOwnProperty.call(obj, k)) {
      str += `${k}=${obj[k]}`;
    }
  }
  return str ? `?${str}` : "";
};

// 一个请求方法
const getList = async (params, { value, refetching }) => {
  const res = await fetch(
    `/node_modules/.vite/deps/solid-js.js${obj2queryStr(
      Object.assign({}, params, refetching)
    )}`
  ).then((res) => res.text());
  // `value` 告诉你 fetcher 的最后一个返回值。如果使用 refetch 函数触发了 fetcher,则 refetching 为 true,也可以是refetch传的数据
  console.log({ value, refetching, params, res });
  return res;
};

const test1 = () => {
  // 表单数据
  const [formData, setFormData] = createSignal({
    v: "52fe8771",
  });

  //  请求参数: 对表单数据进行处理得到
  const queryData = createMemo(() => {
    let data = formData();
    data.v = data.v.trim();
    return data;
  });

  //  发起请求: 每当 queryData 的值发生变化时,都会再次调用getList,并且该值将始终作为第一个参数传递给 getList。
  const [listData, { mutate, refetch }] = createResource(queryData, getList);
  // 设置 listData 的值: 可以调用 mutate 来直接更新 data signal(它的工作方式与任何其他 signal setter 一样)。
  mutate(() => {
    // 这可以设置 listData 的初始值
    return "listData的初始值";
  });

  // 监听到返回值获取loading变化来了做点什么
  createEffect(() => {
    console.log(listData.loading, "loading");
    console.log(listData(), "data");
    console.log(listData.error, "err"); // undefined
  });

  // 点击按钮重新请求
  const handleClick = () => {
    refetch({ timeStamp: new Date().getTime() });
  };

  return (
    <div>
      <xy-button onClick={() => handleClick()}>refetch</xy-button>
    </div>
  );
};

export default test1;

onMount

import { onMount } from "solid-js";

const test1 = () => {
  let myDiv;

  onMount(() => {
    console.log(myDiv);
  });

  return (
    <div>
      <div ref={myDiv}>myDiv</div>
    </div>
  );
};
export default test1;

onCleanup

import { onCleanup } from "solid-js";

const test1 = () => {

  let timer = setInterval(()=>{
    console.log(1)
  },1000)

  // 注册一个清理方法,该方法在当前反应范围的清除或重新计算时执行。可以在任何组件或 Effect 中使用
  // 可以清理定时器,解除事件绑定等。
  onCleanup(() => {
    window.clearInterval(timer)
  });

  return (
    <div>
      
    </div>
  );
};
export default test1;

onError

import { onError } from "solid-js";

const MyComponent = ()=>{
  // 可以被捕获
  throw new Error("MyComponent Error");
}

const MyComponent2 = ()=>{
  onError((err) => {
    console.log("MyComponent2 err is:");
    console.log(err);
  });
  // 可以就地被捕获
  throw new Error("MyComponent2 Error");
}

const MyComponent3 = ()=>{
  onError((err) => {
    // 不可以被捕获
    throw err
  });
  // 可以就地被捕获
  throw new Error("MyComponent2 Error");
}

const test1 = () => {
  onError((err) => {
    console.log("err is:");
    console.log(err);
  });

  // 可以被捕获
  // throw new Error("throw new Error");
  // setTimeout(()=>{
  //   // 不可以被捕获
  //   throw new Error("setTimeout Error");
  // },1000)

  // 不可以被捕获
  // Promise.reject("Promise.reject")

  // setTimeout(() => {
  //   onError((err) => {
  //     console.log("err is:");
  //     console.log(err);
  //   });
  //   // 不可以被捕获
  //   throw new Error("setTimeout Error");
  // }, 1000);

  console.log("render");

  return (
    <div>
      <MyComponent />
      <MyComponent2 />
      <MyComponent3 />
      ------
      {a()}
      ------
    </div>
  );
};
export default test1;

untrack

停止跟踪依赖变化

这样是不行的,界面还会更新。

import { createSignal, untrack } from "solid-js";

const test1 = () => {
  const [a, setA] = createSignal(1);

  const t = setInterval(() => {
    if (a() >= 5) {
      window.clearInterval(t);
      untrack(a);
      return;
    }
    setA(a() + 1);
  }, 1000);


  setTime


  return <div>尝试连接:{a()}</div>;
};
export default test1;

正确的用法

import { createSignal, createEffect,untrack } from "solid-js";

const test1 = () => {
  const [a, setA] = createSignal(0);

  untrack(a);

  createEffect(() => {
    // 只执行一次了
    console.log(untrack(a));
  });

  setA(a() + 100);
  
  setInterval(()=>{
    setA(a() + 100);
  },500)

  // 界面还是在更新
  return <div>{a()}</div>;
};
export default test1;

batch

在块内保持执行下游计算直到结束,以防止不必要的重新计算。Solid Store 的 set 方法、Mutable Store 的数组方法和 effect 会自动将它们的代码打包成批处理。

import { createSignal, createEffect,batch } from "solid-js";

const test1 = () => {
  const [a, setA] = createSignal(0);
  const [b, setB] = createSignal(0);

  batch(a);

  createEffect(() => {
    // 正常下会这执行3遍:初始一遍,setTimeout 设置了两次执行两遍
    // 用了 batch 就只执行一遍
    console.log(a(),b());
  });

  setA(a() + 1);
  setB(b() + 1);

  setTimeout(batch(()=>{
    console.log('执行一遍')
    setA(a() + 1);
    setB(b() + 1);
  }),100)
  
  // setTimeout(()=>{
  //   console.log('执行一遍')
  //   setA(a() + 1);
  //   setB(b() + 1);
  // },100)
  

  // 界面还是在更新
  return <div>{a()}</div>;
};
export default test1;

on

import { createSignal, createEffect, on } from "solid-js";

const test1 = () => {
  const [a, setA] = createSignal("a");
  const [b, setB] = createSignal("b");
  // 只监听 a
  // 等同于:
  // createEffect(() => {
  //   const v = a();
  //   untrack(() => console.log(v, b()));
  // });
  createEffect(on(a, (v) => console.log(v, b()))); // a b
  setInterval(() => {
    setB(b() + 100);
  }, 500);

  return <div>{a()}</div>;
};

const test2 = () => {
  const [a, setA] = createSignal("a");
  // 避免首次执行
  createEffect(on(a, (v) => console.log(v), { defer: true }));
  setA(a() + 100);
  setTimeout(() => {
    setA(a() + 100);
  }, 100);
  console.log("render");
  return <div>{a()}</div>;
};

export default test2;

createRoot

当父组件更新,createRoot 里面的状态不会更新。这可以做缓存。
所有 Solid 代码都应被 createRoot 包裹,因为它们确保释放所有内存/计算,render 中使用了 createRoot,我们就不用手写一个了,大部分情况下不用。

import { createSignal, createEffect, createRoot } from "solid-js";

(() => {
  const [a, setA] = createSignal(0);

  createEffect(() => {
    console.log("a effect01 =", a());
  });
  createEffect(() => {
    console.log("a effect02 =", a());
  });

  // count effect01 = 0
  // count effect02 = 0
  // count effect01 = 1
  // count effect02 = 1

  setA(1);

  return <div>{a()}</div>;
})();

createRoot(() => {
  const [a, setA] = createSignal(0);

  createEffect(() => {
    console.log("a effect01 =", a());
  });
  createEffect(() => {
    console.log("a effect02 =", a());
  });

  // count effect01 = 1
  // count effect02 = 1

  setA(1);

  return <div>{a()}</div>;
})

const test1 = () => {
  return <div></div>;
};
export default test1;

getOwner

import { createSignal, createEffect,getOwner } from "solid-js";

const test1 = () => {
  const [a, setA] = createSignal(0);

  createEffect(() => {
    console.log();
    console.log(getOwner());
  });

  setA(a() + 1);
  
  // 获取拥有当前运行代码的响应范围
  const owner = getOwner()
  console.log(owner)
  console.log(owner.componentName) // "test1"
  console.log(owner.value) // div
  console.log(owner.props) // {}
  console.log(owner.name) // "c-1-1-1"

  return <div>{a()}</div>;
};
export default test1;

runWithOwner

应该就是提供一个所有者,执行一些所有者下才执行的动作。
在所有者者范围内才能使用 useContext;和清理 createEffect 监听。

import {
  createSignal,
  createEffect,
  getOwner,
  runWithOwner,
  useContext,
  createContext,
} from "solid-js";

let owner = null;
let Ctx = null
setTimeout(() => {
  // 此回调在没有所有者的情况下运行。
  // 通过 runWithOwner 恢复所有者:
  runWithOwner(owner, () => {
    console.log(Ctx,'Ctx')
    const foo = useContext(Ctx);
    createEffect(() => {
      console.log(foo,'foo');
    });
  });
}, 2000);

const MyComponent = () => {
  const [state] = useContext(Ctx);
  return <div>{JSON.stringify(state)}</div>;
};

const test1 = () => {

  Ctx = createContext([{ count: 0 }, {}]);
  
  // 获取拥有当前运行代码的响应范围
  owner = getOwner();
  console.log(owner,'owner');

  return (
    <Ctx.Provider value={[{ count1: 0 }]}>
      <MyComponent />
    </Ctx.Provider>
  );
};
export default test1;

mergeProps


import { createSignal, createEffect, mergeProps } from "solid-js";

const MyComponents = (props) => {
  // 默认 props
  props = mergeProps({ name: "Smith" }, props);
  // 克隆 props (克隆的和不克隆的一样,修改了一样会影响到外面)
  //   setTimeout(()=>{
  // let newProps = mergeProps(props);
  // newProps.obj.a[0] = 100;
  // newProps.obj.b = 100;
  // newProps.signalObj.a[0] = 100;
  // newProps.signalObj.b = 100;
  // props.obj.a[0] = 100;
  // props.obj.b = 100;
  // props.signalObj.a[0] = 100;
  // props.signalObj.b = 100;
  //   },100)
  let newProps = mergeProps(props);
  // newProps.obj.a[0] = 100;
  // newProps.obj.b = 100;
  newProps.signalObj.a[0] = 100;
  newProps.signalObj.b = 100;
  // props.obj.a[0] = 100;
  // props.obj.b = 100;
  //   props.signalObj.a[0] = 100;
  //   props.signalObj.b = 100;
  //   props.name = "122";
  //   newProps.name = 'Jane'; // 不能直接改它会报错
  return (
    <>
      {props.name} {props.children}
    </>
  );
};

const MyComponents2 = (props = { name: "Smith" }) => {
  return (
    <>
      {props.name}
      <br />
      {props.obj.a[0]}
      <br />
      {props.obj.b}
      <br />
      {props.signalObj.a[0]}
      <br />
      {props.signalObj.b}
    </>
  );
};

const test1 = () => {
  // 普通的引用值在子组件中被修改会影响到界面,createEffect 监听不到
  // 响应的引用值在子组件中被修改会影响到界面,createEffect 也监听得到
  // <MyComponents signalObj={signalObj} /> <MyComponents signalObj={signalObj()} /> 这两种都行
  //  props 属性不能修改(props.name = "122";),会报错。除非是对象
  // newProps = mergeProps(props); newProps和props没什么区别
  var name = "Jack";
  var [signalObj, setSignalObj] = createSignal({ a: [1, 2, 3], b: 1 });
  var obj = { a: [1, 2, 3], b: 1 };
  createEffect(() => {
    console.log("执行一次:打印obj", obj);
    console.log("执行一次:打印obj.b", obj.b);
    console.log("执行一次:打印signalObj", signalObj());
    console.log("执行一次:打印signalObj.b", signalObj().b);
  });
  return (
    <>
      <MyComponents
        name={name}
        obj={obj}
        signalObj={signalObj()}
      ></MyComponents>
      ---------------------------------------------------
      <MyComponents2
        name={name}
        obj={obj}
        signalObj={signalObj()}
      ></MyComponents2>
    </>
  );
};
export default test1;

splitProps

分割 props。


import { splitProps } from "solid-js";

const MyComponents = (props = { name: "Smith" }) => {
  console.log(props); // {a: 1, b: 2, c: 3, d: 4, e: 5, foo: "bar"}
  const [vowels, consonants, leftovers] = splitProps(
    props,
    ["a", "e"],
    ["b", "c", "d"]
  );
  console.log(vowels); // {a: 1, e: 5}
  console.log(consonants); // {b: 2, c: 3, d: 4}
  console.log(leftovers.foo); // bar
};

const test1 = () => {
  return (
    <>
      <MyComponents a={1} b={2} c={3} d={4} e={5} foo="bar"></MyComponents>
    </>
  );
};
export default test1;

useTransition

TODO
用于批量异步更新延迟提交,直到所有异步进程完成。这与 Suspense 相关联,并且仅跟踪在 Suspense 边界下读取的资源。

startTransition

TODO
类似于useTransition,除了没有关联的 pending 状态。这个可以直接用来启动 Transition。

observable

TODO

from

TODO

mapArray

import { createSignal, mapArray, For } from "solid-js";

const test1 = () => {
  var [arr, setArr] = createSignal([
    {
      id: 1,
      name: "xiaom",
      description: "xiaomi",
    },
    {
      id: 2,
      name: "xiaom2",
      description: "xiaomi2",
    },
  ]);

  //   通过引用缓存每个 item,以减少不必要的更新映射。它只对每个值运行一次映射函数,然后根据需要移动或删除它。index 参数是一个 signal。map 函数本身不跟踪。

  //   <For> 控制流的底层工具类。

  //   感觉没什么L用

  const mapped = mapArray(arr, (model) => {
    console.log(model);
    const [name, setName] = createSignal(model.name);
    const [description, setDescription] = createSignal(model.description);

    return {
      id: model.id,
      get name() {
        return name();
      },
      get description() {
        return description();
      },
      setName,
      setDescription,
    };
  });

  setTimeout(() => {
    setArr([
      {
        id: 1,
        name: "xiaom",
        description: "xiaomi",
      },
    ]);
  }, 1000);

  return (
    <div>
      <For each={mapped()} fallback={<div>Loading...</div>}>
        {(item) => <div>{item.name}</div>}
      </For>
    </div>
  );
};

export default test1;

indexArray

import { createSignal, indexArray, For } from "solid-js";

const test1 = () => {
  var [arr, setArr] = createSignal([
    {
      id: 1,
      name: "xiaom",
      description: "xiaomi",
    },
    {
      id: 2,
      name: "xiaom2",
      description: "xiaomi2",
    },
  ]);

  //   类似于mapArray,除了它按 index 映射。该 item 是一个 signal,index 现在是常数。

  const mapped = indexArray(arr, (model) => {
    console.log(model);

    return {
      get id() {
        return model.id;
      },
      get name() {
        return model().name;
      },
      get description() {
        return description();
      },
    };
  });

  setTimeout(() => {
    setArr([
      {
        id: 1,
        name: "xiaom",
        description: "xiaomi",
      },
    ]);
  }, 1000);

  return (
    <div>
      <For each={mapped()} fallback={<div>Loading...</div>}>
        {(item) => <div>{item.name}</div>}
      </For>
    </div>
  );
};

const test2 = () => {
  // Solid.js 中的 IndexArray 是一个特殊的数组,它可以用于优化列表渲染的性能。
  // 在 Solid.js 中,当我们使用 for...of 循环或 map 函数来渲染一组数据时,每当数据发生变化时,Solid.js 都会重新渲染整个列表。这种方式可能会导致性能问题,特别是在大量数据的情况下。
  // 在上面的例子中,我们使用 IndexArray 包装了一个普通的数组 items,并将其传递给 map 函数来渲染列表。key 属性使用了每一项的索引作为唯一标识。当数据发生变化时,只有发生变化的项会被重新渲染,从而提高了性能。
  //   需要注意的是,IndexArray 仅适用于静态列表(即不包含过滤、排序等动态操作的列表)。因为 IndexArray 使用了标识符来区分每一项,如果列表中的项发生动态变化,可能会导致标识符的重复或丢失,从而引发错误。
  var [items] = createSignal(["apple", "banana", "cherry"]);
  const indexedArray = indexArray(items, (item) => item);
  return (
    <div>
      <ul>
        {indexedArray().map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
};

export default test2;

// TODO

参考:
https://www.npmjs.com/package/solid-js/v/1.3.9
https://gitee.com/petter_pan/soidjs-demo

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值