Skip to content

description: 如何安装和使用库

入门指南

PreffX 是一个自信的 JS 库,用于创建响应式 DOM。它受到 React 和 Preact 的启发,但提供了自己的基于信号的方法。

⚠️ 该项目目前处于实验阶段,请勿在生产环境中使用 ⚠️

基本原则

  • 类似 React 的 JSX 语法;
  • Preact signals 作为响应式核心;
  • 只有信号会触发重新渲染;
  • 每个组件只执行一次;
  • 组件 props 作为第一个参数传入,所有工具作为第二个参数传入 - 无需导入它们;
  • 支持同步和异步函数组件;
  • 区分属性和特性(所有属性都以 $ 为前缀)- 例如,$value 是一个属性,而 value 是一个特性。

安装

尝试 Vite + PreffX 演示

示例

  • 简单计数器:
tsx
import type { PC } from 'preffx';

export const App: PC = (props, { signal }) => {
    const count = signal(0);
    return <button
        onClick={() => {
            count.value += 1
        }}
    >
        Count is {count}
    </button>
};
  • 如何创建元素引用:
tsx
import type { PC } from 'preffx';

export const App: PC = (props, { signal }) => {
    const signalRef = signal();
    return <div $ref={signalRef}>
        <div
          $ref={(refVal) => {
            // 在元素挂载后调用,refVal = HTMLDivElement
            // 在元素销毁前调用,refVal = null
          }}
        >
            Refs
        </button>
    </div>
};
  • 生命周期钩子:
tsx
import type { PC } from 'preffx';

export const App: PC = (props, { onMount, onDestroy }) => {
    const { count } = props;

    onMount(() => {
        // 挂载逻辑
    });
    
    onDestroy(() => {
        // 销毁逻辑
    });
    return <button
        onClick={() => {
            count.value += 1
        }}
    >
        Count is {count}
    </button>
};
  • 列表渲染:
tsx
import type { PC } from 'preffx';

export const App: PC = (props, { For }) => {
    const items = signal([
        {
            name: 'First'
        },
        {
            name: 'Second'
        }
    ]);

    return <ul>
        <For
            items={items}
            callback={(item) => <li>Item with name: {item.name}</li>}
            fallback={<li>No items</li>}
        />
    </ul>;
};
  • 上下文处理:
tsx
import type { PC } from 'preffx';

const contextKey = 'ctx-counter';

const AnotherComponent: PC = (props, { context }) => {
    // 读取上下文
    const counter = context[contextKey];
    return <span>
        {counter}
    </span>;
};

export const App: PC = (props, { signal, context }) => {
    const counter = signal(0);
    // 修改上下文
    context[contextKey] = counter;
    return <p>
        {valueFromContext}
        <AnotherComponent />
    </p>;
};
  • 异步组件:
tsx
import type { APC } from 'preffx';
import { getData } from './data';
import { AnotherComponent, AnotherAsyncComponent } from './components';

const AsyncComponent: APC<{
    name: string;
}> = async (props, utils) => {
    const data = await getData()
    const componentRoot = await <AnotherAsyncComponent name='nested'/>;
    return <div>
        <AnotherComponent data={data} />
        {componentRoot}
    </div>;
}
  • 错误处理:
tsx
import type { PC } from 'preffx';
import { AnotherComponent } from './components';

export const App: PC = (props, { Catch }) => {
    return <div>
        有时组件会返回错误
        <Catch fallback={<div>Catched!</div>}>
            <AnotherComponent />
        </Catch>
    </div>;
};
  • 延迟值处理:
tsx
import type { PC } from 'preffx';
import { AsyncComponent } from './components';

export const App: PC = (props, { computed, Defer }) => {
    const def = computed(() => <AsyncComponent id={props.id} />);
    return <Defer
        value={def}
        initial={<div>Please wait</div>}
    />;
};
  • 传送门:
tsx
import type { PC } from 'preffx';

export const App: PC = (props, { Portal }) => {
    return <div>
        <span>当前树中的某些文本</span>
        <Portal root={document.getElementById('portal')} >
            <div>传送门中的文本</div>
        </Portal>
    </div>;
};
  • 唯一标识符:
tsx
import type { PC } from 'preffx';

export const App: PC = (props, { id }) => {
    // 获取唯一 id
    const inputId = id();
    return <div>
        <label>
            密码:
            <input
                type="password"
                aria-describedby={inputId}
            />
        </label>
        <p id={inputId}>
            密码应至少包含 18 个字符
        </p>
    </div>;
};

根据 Apache-2.0 许可证发布。