Hooks 与 Context
App 页面中的状态、副作用与共享值。
在函数组件顶层按固定顺序调用 Hooks,并从 supernode/app 导入。Hooks 只在 app.show() 中运行;在其他地方调用(包括小组件视图)会抛出异常。
useState
useState(initial) 返回 [value, setValue]。initial 可以是值,也可以是只执行一次、用于生成初值的函数。setValue 接受下一个值,或更新函数 (current) => next。相等的值(Object.is)会跳过重新渲染;setter 的引用保持稳定。
import { app } from "supernode";
import { Column, Text, TextField, useState } from "supernode/app";
function Profile() {
const [name, setName] = useState(() => "SuperNode");
return (
<Column spacing={12}>
<Text fontSize={24}>你好,{name}</Text>
<TextField value={name} placeholder="姓名" onValueChange={setName} />
</Column>
);
}
await app.show({ views: <Profile /> });useReducer
useReducer(reducer, initialArg, init?) 返回 [state, dispatch],通过 reducer 更新状态。提供 init 时,初始状态为 init(initialArg),且该函数只运行一次。dispatch 的引用保持稳定,并始终使用最新的 reducer 处理 action。
import { app } from "supernode";
import { Column, Text, TextField, useReducer } from "supernode/app";
function reducer(state: { name: string }, name: string) {
return { name };
}
function Form() {
const [state, dispatch] = useReducer(reducer, "SuperNode", name => ({ name }));
return (
<Column spacing={12}>
<Text fontSize={24}>你好,{state.name}</Text>
<TextField value={state.name} placeholder="姓名" onValueChange={dispatch} />
</Column>
);
}
await app.show({ views: <Form /> });useEffect
useEffect(setup, dependencies?) 在原生页面挂载或更新后执行 setup。setup 可返回同步 cleanup。[] 表示每次挂载执行一次;省略依赖列表则每次渲染后都执行。cleanup 会在下一次 setup 之前以及页面关闭时运行。不支持异步 setup。
import { app } from "supernode";
import { Text, useEffect, useState } from "supernode/app";
function Clock() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const timer = setInterval(() => setSeconds(value => value + 1), 1000);
return () => clearInterval(timer);
}, []);
return <Text>{seconds} 秒</Text>;
}
await app.show({ views: <Clock /> });useMemo
useMemo(calculate, dependencies?) 在依赖值保持相等时复用 calculate 的结果;某个依赖变化时重新计算。[] 表示每次挂载计算一次;省略依赖列表则每次渲染都计算。依赖列表的长度在多次渲染中必须保持一致。
import { app } from "supernode";
import { Column, Text, TextField, useMemo, useState } from "supernode/app";
function Preview() {
const [title, setTitle] = useState("SuperNode");
const label = useMemo(() => title.trim() || "未命名", [title]);
return (
<Column spacing={12}>
<Text fontSize={24}>{label}</Text>
<TextField value={title} placeholder="标题" onValueChange={setTitle} />
</Column>
);
}
await app.show({ views: <Preview /> });useCallback
useCallback(callback, dependencies?) 在依赖保持相等时复用同一个函数实例。适合作为子组件或 effect 的依赖。[] 会在组件生命周期内保留该函数;省略依赖列表则每次渲染都返回新函数。
import { app } from "supernode";
import { Column, Text, TextField, useCallback, useState } from "supernode/app";
function Profile() {
const [name, setName] = useState("");
const onValueChange = useCallback((value: string) => setName(value.trim()), []);
return (
<Column spacing={12}>
<Text>你好,{name || "访客"}</Text>
<TextField value={name} placeholder="姓名" onValueChange={onValueChange} />
</Column>
);
}
await app.show({ views: <Profile /> });useContext
createContext(defaultValue) 创建带 Provider 与 Consumer 的 context。useContext(context) 读取最近的 Provider 值;若不存在则使用默认值。Consumer 的子节点必须是函数。
import { app } from "supernode";
import { createContext, Text, useContext } from "supernode/app";
const Greeting = createContext("你好");
function Message() {
const greeting = useContext(Greeting);
return <Text>{greeting}</Text>;
}
await app.show({
views: (
<Greeting.Provider value="欢迎">
<Message />
</Greeting.Provider>
),
});使用规则
状态更新会批量调度渲染。保持渲染过程纯净,在 effect cleanup 中释放外部资源。组件外调用 Hook、改变 Hook 调用顺序、卸载后更新状态都会报错。
小组件只渲染一次,不支持 Hooks 与 Context,详见 Widget。