# Rules of Hooks

*Ivy hooks (functions starting with `Use...`) are a powerful feature that lets you use [state](./02_Core/03_UseState.md) and other Ivy features. However, hooks rely on a strict call order to function correctly. Follow these rules to ensure your hooks work as expected.*

## Overview

Ivy hooks provide a way to add stateful logic and side effects to your [views](../01_Onboarding/02_Concepts/02_Views.md). To work correctly, hooks must be called in a consistent order on every render.

Key principles:

- **Consistent Call Order** - Hooks must be called in the same order on every render
- **Top-Level Only** - Hooks can only be called at the top level of your component
- **Valid Context** - Hooks can only be called from Views or other hooks
- **Compile-Time Validation** - The Ivy.Analyser package enforces these rules automatically

> **Tip:** The Ivy.Analyser package automatically validates hook usage at compile time, catching violations before your code runs. This helps prevent runtime errors and ensures your hooks work correctly.

## The Rules

Ivy hooks follow two fundamental rules that ensure they work correctly:

### 1. Only Call Hooks at the Top Level

**Don't call hooks inside loops, conditions, or nested functions.** Always use hooks at the top level of your component's `Build` method (or custom hook).

```mermaid
flowchart TD
    A["Component Render"] --> B{Where are hooks called?}
    
    B --> C["Top level of Build()"]
    B --> D["Inside if/else"]
    B --> E["Inside loop"]
    B --> F["Inside nested function"]
    
    C --> G["Valid<br/>Same order every render<br/>Hooks work correctly"]
    D --> H["Invalid<br/>Order may change<br/>IVYHOOK002 error"]
    E --> I["Invalid<br/>Order may change<br/>IVYHOOK003 error"]
    F --> J["Invalid<br/>May not execute<br/>IVYHOOK001 error"]
    
    G --> K["Hooks preserve state<br/>Component works correctly"]
    H --> L["Compile error<br/>Fix hook placement"]
    I --> L
    J --> L
```

### 2. Only Call Hooks from Ivy Views

**Don't call hooks from regular C# functions.** Hooks can only be called from:

- Ivy [views](../01_Onboarding/02_Concepts/02_Views.md) (inside `Build` method)
- Custom hooks (functions starting with `Use...`)

```mermaid
flowchart TD
    A["Want to use a hook?"] --> B{Where are you calling it?}
    
    B --> C["Inside ViewBase.Build()"]
    B --> D["Inside custom UseX hook"]
    B --> E["Inside regular method"]
    B --> F["Inside service class"]
    
    C --> G["Valid<br/>Hooks work correctly"]
    D --> G
    E --> H["Invalid<br/>IVYHOOK001 error"]
    F --> H
    
    G --> I["Hook executes<br/>State preserved"]
    H --> J["Compile error<br/>Move to View or custom hook"]
```

## Why These Rules Matter

Hooks rely on call order to preserve [state](./02_Core/03_UseState.md) between renders. When hooks are called in the same order every time, Ivy can correctly match each hook call with its stored state.

### How Hook Order Works

```mermaid
sequenceDiagram
    participant C as Component
    participant H as Hook System
    participant S as State Storage
    
    Note over C,S: First Render
    C->>H: UseState(0) - Hook #1
    H->>S: Store state at index 0
    C->>H: UseState("") - Hook #2
    H->>S: Store state at index 1
    C->>H: UseEffect(...) - Hook #3
    H->>S: Store effect at index 2
    
    Note over C,S: Second Render (same order)
    C->>H: UseState(0) - Hook #1
    H->>S: Retrieve state from index 0
    C->>H: UseState("") - Hook #2
    H->>S: Retrieve state from index 1
    C->>H: UseEffect(...) - Hook #3
    H->>S: Retrieve effect from index 2
    
    Note over C,S: Third Render (different order - ERROR!)
    C->>H: UseState("") - Hook #1 (wrong!)
    H->>S: Retrieve from index 0 (wrong state!)
    C->>H: UseState(0) - Hook #2 (wrong!)
    H->>S: Retrieve from index 1 (wrong state!)
    Note right of H: State mismatch!<br/>Component breaks
```

## Common Violations and Solutions

### IVYHOOK001: Hook used outside valid context

This error occurs when you try to use a hook outside of a View's `Build` method or another hook.

**Bad**: Hook in Regular Method

```csharp
public class MyService
{
    public void DoSomething()
    {
        var state = UseState(0); // Error! Not inside a View.
    }
}
```

**Good**: Hook in View

```csharp
public class MyView : ViewBase
{
    public override object Build()
    {
        var state = UseState(0); // OK - inside ViewBase.Build()
        return Layout.Vertical(
            Text.P($"Value: {state.Value}"),
            new Button("Increment", _ => state.Set(state.Value + 1))
        );
    }
}
```

### IVYHOOK002: Conditional Hook Usage

This error occurs if a hook call is wrapped in an `if` statement. Hook calls must be unconditional.

**Bad**: Conditional Hook

```csharp
public override object Build()
{
    if (condition) {
        var state = UseState(0); // Error! Hook might not run.
    }
    return Layout.Vertical();
}
```

**Good**: Unconditional Hook

```csharp
public class ConditionalStateDemo : ViewBase
{
    public override object Build()
    {
        // Always call the hook, handle logic afterwards
        var state = UseState(0);
        var condition = UseState(true);
        
        return Layout.Vertical(
            Layout.Horizontal(
                new Button("Toggle Condition", _ => condition.Set(!condition.Value)),
                new Button("Increment", _ => state.Set(state.Value + 1))
            ),
            condition.Value 
                ? Text.P($"State value: {state.Value}")
                : Text.P("Condition is false")
        );
    }
}
```

### IVYHOOK003: Hook inside a loop

Hooks cannot be called inside `for`, `foreach`, `while` loops. Each item in a loop needs its own component instance to use hooks correctly.

**Bad**: Hook in Loop

```csharp
public override object Build()
{
    var items = UseState(new List<string> { "Item 1", "Item 2" });
    
    // Error! Hook called multiple times with unpredictable order
    foreach (var item in items.Value) {
        var count = UseState(0); // IVYHOOK003: Hook inside a loop
    }
    return Layout.Vertical();
}
```

**Good**: Component per Item

Each item gets its own component, allowing each to safely use hooks:

```csharp
public class ItemListDemo : ViewBase
{
    public override object Build()
    {
        var items = UseState(new List<string> { "Apple", "Banana", "Cherry" });
        var newItem = UseState("");
        
        return Layout.Vertical(
            Text.H3("Shopping List"),
            Layout.Horizontal(
                newItem.ToTextInput().Placeholder("Add item..."),
                new Button("Add", _ => {
                    if (!string.IsNullOrWhiteSpace(newItem.Value))
                    {
                        items.Set(items.Value.Append(newItem.Value).ToList());
                        newItem.Set("");
                    }
                })
            ),
            new Separator(),
            Layout.Vertical(items.Value.Select((item, index) => new ShoppingItemView(item).Key($"{item}-{index}")).ToArray())
        );
    }
}

public class ShoppingItemView : ViewBase
{
    private readonly string _itemName;
    
    public ShoppingItemView(string itemName)
    {
        _itemName = itemName;
    }
    
    public override object Build()
    {
        // Hook is called at top level - OK!
        // Each ShoppingItemView instance has its own count state
        var count = UseState(1);
        
        return Layout.Horizontal(
            Text.P($"{_itemName} x {count.Value}"),
            new Button("-", _ => count.Set(Math.Max(1, count.Value - 1))),
            new Button("+", _ => count.Set(count.Value + 1))
        );
    }
}
```

### IVYHOOK005: Hook not at top of method

Hooks must be called before any other statements (like `return`, `throw`, etc) to ensure they always run.

**Bad**: Early Return Before Hook

```csharp
public override object Build()
{
    if (User == null) return Text("Login required");
    
    var state = UseState(0); // Error! This hook might not run.
    return Layout.Vertical();
}
```

**Good**: Hooks First

```csharp
public class EarlyReturnDemo : ViewBase
{
    public override object Build()
    {
        // Always call hooks first
        var state = UseState(0);
        var user = UseState(() => (string?)null);
        
        // Then handle early returns
        if (user.Value == null) 
            return Text.P("Login required");
        
        return Layout.Vertical(
            Text.P($"Welcome, {user.Value}!"),
            Text.P($"Count: {state.Value}"),
            new Button("Increment", _ => state.Set(state.Value + 1))
        );
    }
}
```

## Hook Detection

The analyzer automatically detects hooks by their naming convention:

| Pattern | Valid | Examples |
|---------|-------|----------|
| Starts with `Use` + uppercase letter | Yes | `UseState`, `UseEffect`, `UseCustomHook`, `UseMyFeature` |
| Starts with `Use` but lowercase | No | `useState`, `useEffect` |
| Doesn't start with `Use` | No | `GetState`, `CreateEffect` |
| `Use` but no uppercase after | No | `Use`, `Useless` |

```mermaid
flowchart LR
    A[Hook Name] --> B{Pattern: Use + Uppercase?}
    B -->|Yes| C[Valid Hook]
    B -->|No| D[Invalid Hook]
    
    C --> C1[UseState<br/>UseEffect<br/>UseReducer<br/>UseMemo]
    D --> D1[useState<br/>Use<br/>GetState]
```

**Valid Examples:**

- [`UseState`](./02_Core/03_UseState.md), [`UseEffect`](./02_Core/04_UseEffect.md), `UseCustomHook`, `UseMyFeature`, [`UseReducer`](./02_Core/07_UseReducer.md), [`UseMemo`](./02_Core/05_UseMemo.md)

**Invalid Examples:**

- `useState` (lowercase 's')
- `Use` (no uppercase after 'Use')
- `Useless` (no uppercase after 'Use')
- `GetState` (doesn't start with 'Use')

This means any custom hooks you create following the `UseX` pattern will be automatically validated by the analyzer.

## Troubleshooting Guide

```mermaid
flowchart TD
    A["Hook error or unexpected behavior?"] --> B{What's the error?}
    
    B --> C["IVYHOOK001<br/>Outside valid context"]
    B --> D["IVYHOOK002<br/>Conditional hook"]
    B --> E["IVYHOOK003<br/>Hook in loop"]
    B --> F["IVYHOOK005<br/>Not at top"]
    B --> G["State not updating"]
    
    C --> C1["Move hook to ViewBase.Build()<br/>Or create custom hook<br/>Check method context"]
    D --> D1["Remove if/else around hook<br/>Call hook unconditionally<br/>Move condition after hook"]
    E --> E1["Extract to component<br/>Create ItemView class<br/>Call hook in component"]
    F --> F1["Move hooks to top<br/>Before any returns<br/>Before any logic"]
    G --> G1["Check hook order<br/>Verify same order every render<br/>Check for conditional calls<br/>Review state updates"]
    
    C1 --> H["Problem solved?"]
    D1 --> H
    E1 --> H
    F1 --> H
    G1 --> H
    
    H -->|Yes| I["Great! Your hooks are working correctly"]
    H -->|No| J["Review hook rules<br/>Check analyzer errors<br/>Seek help in community"]
```

## Quick Reference

```mermaid
flowchart LR
    A[Call Hook?] --> B{In View Build<br/>or custom hook?}
    B -->|No| C[Don't Call]
    B -->|Yes| D{At top level,<br/>same order,<br/>before conditionals?}
    D -->|No| C
    D -->|Yes| E[Call Hook]
    
    C --> C1[Not in loop<br/>Not in if/else<br/>Not in nested function<br/>Not after return]
```

**Rules Checklist:**

- In [view](../01_Onboarding/02_Concepts/02_Views.md) Build method or custom hook
- At top level of Build method
- Same order every render
- Before all conditional logic
- Not in loops, conditionals, or nested functions

## See Also

- [State Management](./02_Core/03_UseState.md) - Using UseState hook
- [Effects](./02_Core/04_UseEffect.md) - Using UseEffect hook
- [Memoization](./02_Core/05_UseMemo.md) - Using UseMemo and UseCallback
- [Views](../../../01_Onboarding/02_Concepts/02_Views.md) - Understanding Ivy Views