Hooks
Hooks 只能通过当前函数组件的 ComponentContext context 调用。CSX 函数组件方法的
第一个参数必须是 ComponentContext context;普通 C# 根组件则从
window.Render(context => { ... }) 接收它。
Hooks 按 render 调用顺序保存状态,规则与 React 类似:不要在条件分支、循环或 early return
之后改变 hook 调用顺序。顺序变化会抛出 InvalidOperationException,避免状态槽错位。
UseState
var count = context.UseState(0);
var button = new Button($"Count {count.Value}");
button.OnClick += (_, _) => count.Update(static value => value + 1);
return button;
Set(value) 或 Update(updater) 会在值变化时请求 render。离线测试中可以用
app.Flush() 等待已调度的 render 完成;异步场景可等待 app.PendingRender。
UseReducer
var todos = context.UseReducer(
static (state, action) => action switch
{
TodoAction.Add add => state.Append(new Todo(add.Title)).ToArray(),
TodoAction.Toggle toggle => state
.Select(item => item.Id == toggle.Id ? item with { Done = !item.Done } : item)
.ToArray(),
_ => state,
},
Array.Empty<Todo>());
Dispatch(action) 会通过当前 reducer 计算新状态并触发 render。
UseMemo
var openCount = context.UseMemo(
() => todos.Value.Count(static item => !item.Done),
todos.Value);
依赖数组用 object.Equals 比较。依赖未变化时直接返回上一次的值。
UseEffect
context.UseEffect(
() =>
{
Console.WriteLine("committed");
return new SubscriptionCleanup();
},
count.Value);
Effect 在当前 render 的 DOM frame 提交后运行。依赖变化时会先 dispose 上一个 cleanup, 再运行新的 effect。