生命周期

规则

使用生命周期hooks时,必须遵守以下规则:

  • 他们只能在 component$里调用
  • 他们只能在普通函数根层级/箭头函数context里被调用, 不能在条件块语句里调用。
  • 他们只能被其他 use*$ 方法调用, 用于组合
useHook() // <-- ❌ does not work

export default component$(() => {
  useHook() // <-- ✅ does work
  if (condition) {
    useHook() // <-- ❌ does not work
  }
  const myQrl = $(() => useHook()) // <-- ✅ does work
  return <button onClick$={() => useHook()}></button> // <-- ✅ does work
})

const useCustomHook = () => {
  useHook() // <-- ✅ does work
}

useMount$()

useMount$() 可以注册一个hook,当组件创建完时,会执行这个hook。 useMount$() 会阻塞组件渲染 直到 useMount$() 回调 解析完。 (这对异步取数据和直到拿到数据再延迟渲染是有用的,保证了渲染的组件包含数据。)

同时 useMount$() 既可以在服务端也可以在客户端执行, 它只执行一次。(或者在客户端或者在服务端, 取决于组件首先在哪里渲染)

还有一个 useServerMount$() hook 有同样的作用但只能在服务端使用。

Example

export const Cmp = component$(() => {
  const store = useStore({
    users: [],
  });
  useMount$(async () => {
    // This code will run on component creation to fetch the data.
    store.users = await db.requestUsers();
  });
  return (
    <>
      {store.users.map((user) => (
        <User user={user} />
      ))}
    </>
  );
});

interface User {
  name: string;
}

export function User(props: { user: User }) {
  return <div>Name: {props.user.name}</div>;
}

useServerMount$()

useServerMount$() 注册一个server-mounted hook,只在第一次mounted时在服务端运行。

例子

export const Cmp = component$(() => {
  const store = useStore({
    users: [],
  });
  useServerMount$(async () => {
    // This code will ONLY run once in the server, when the component is mounted
    store.users = await db.requestUsers();
  });
  return (
    <>
      {store.users.map((user) => (
        <User user={user} />
      ))}
    </>
  );
});

interface User {
  name: string;
}

export function User(props: { user: User }) {
  return <div>Name: {props.user.name}</div>;
}

useWatch$()

当跟踪的输入改变时 watchFn 重新运行。

使用 useWatch 跟踪一系列输入值的改变情况, 当这些输入有改变时,重新执行watchFn

watchFn只有在输入变化的时候才执行。 为了跟踪这些输入,要使用track函数包裹这些属性。 这样就会创建一个订阅。这个订阅会触发watchFn函数重新执行。

还有一个 useClientEffect$() hook 有同样的作用但只在客户端运行。

例子

useWatch函数用来观察state.count 属性,state.count变化了就会引起watchFn执行。 而watchFn执行又会更新state.doubleCount的值,使其变为state.count的两倍。

export const Cmp = component$(() => {
  const store = useStore({
    count: 1,
    doubleCount: 0,
    debounced: 0,
  });
  // Double count watch
  useWatch$(({ track }) => {
    const count = track(() => store.count);
    store.doubleCount = 2 * count;
  });
  // Debouncer watch
  useWatch$(({ track }) => {
    const doubleCount = track(() => store.doubleCount);
    const timer = setTimeout(() => {
      store.debounced = doubleCount;
    }, 2000);
    return () => {
      clearTimeout(timer);
    };
  });

  return (
    <>
      <div>
        {store.count} / {store.doubleCount}
      </div>
      <div>{store.debounced}</div>
    </>
  );
});

useClientEffect$()

当跟踪的输入改变时,重新运行watchFn

如果没有使用track,它只执行一次。

例子

export const Timer = component$(() => {
  const store = useStore({
    count: 0,
  });
  useClientEffect$(() => {
    // Only runs in the client
    const timer = setInterval(() => {
      store.count++;
    }, 500);
    return () => {
      clearInterval(timer);
    };
  });
  return <>{store.count}</>;
});
Made with ❤️ by