# Mobx React Form Computed

> Reactive computed props and autorun for mobx-react-form — computed field values, autorun-derived totals, reactive row calculations.

- **Type:** Skill
- **Install:** `agentstack add skill-foxhound87-skills-mobx-react-form-computed`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [foxhound87](https://agentstack.voostack.com/s/foxhound87)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [foxhound87](https://github.com/foxhound87)
- **Source:** https://github.com/foxhound87/skills/tree/main/mobx-react-form-computed

## Install

```sh
agentstack add skill-foxhound87-skills-mobx-react-form-computed
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Skill: mobx-react-form-computed

## Mission

Guide the user through implementing **reactive computed values** and **autorun-derived state** in mobx-react-form.

Use this skill when the user needs to:
- Define computed field values (dynamic values from other fields)
- Calculate row totals in array forms (e.g., cart qty × amount)
- Derive grand totals from multiple fields
- Reactively update fields based on other field changes
- Use MobX `autorun()` for complex derived state

## Two Approaches

| Approach | When to Use |
|----------|-------------|
| **Computed Field Props** | Simple derived values based on other fields |
| **MobX autorun()** | Complex multi-field calculations, side effects |

## Computed Field Props

### Basic computed value

The `computed` prop is a function that returns a dynamic value. It receives `{ form, field }`:

```javascript
const fields = ['myComputedField', 'mySwitch'];

const values = {
  myComputedField: ({ form, field }) =>
    form.$('mySwitch')?.value ? 'a' : 'b',
  mySwitch: false,
};

const types = {
  mySwitch: 'checkbox',
};

const form = new Form({ fields, values, types }, {
  options: { strictSelect: false }, // required for computed props
});
```

> **Important**: Set `strictSelect: false` because the computed function may access fields before they exist.

### Computed props on any field property

In addition to `value`, computed functions can be defined on: `label`, `placeholder`, `disabled`, `rules`, `related`, `deleted`, `validatedWith`, `validators`, `bindings`, `extra`, `options`, `autoFocus`, `inputMode`.

```javascript
const fields = {
  email: {
    label: ({ form, field }) =>
      form.$('useWorkEmail')?.value ? 'Work Email' : 'Personal Email',
    placeholder: ({ form }) =>
      form.$('useWorkEmail')?.value ? 'Enter work email' : 'Enter personal email',
    rules: 'required|email',
  },
  useWorkEmail: {
    type: 'checkbox',
    value: false,
  },
};

new Form({ fields }, { options: { strictSelect: false } });
```

### Computed in separated mode

```javascript
const fields = ['myComputedField', 'mySwitch'];

const computed = {
  myComputedField: ({ form }) => form.$('mySwitch')?.value ? 'a' : 'b',
};

new Form({ fields, computed, values: { mySwitch: false } }, {
  options: { strictSelect: false },
});
```

### Computed for nested array fields

Use the special `computed` field prop with a full field path — applied when `add()` creates new items:

```javascript
const fields = [
  "products[].name",
  "products[].qty",
  "products[].amount",
  "products[].total",
  "total"
];

const computed = {
  "products[].total": ({ field }) => {
    const qty = field.container()?.$("qty")?.value;
    const amount = field.container()?.$("amount")?.value;
    return qty * amount;
  },
  total: ({ form }) =>
    form.$("products")?.reduce((acc, field) =>
      acc + (field.$("total")?.value || 0), 0
    ),
};

const form = new Form({ fields, computed }, {
  options: { strictSelect: false, autoParseNumbers: true },
});
```

> Note: `autoParseNumbers: true` ensures qty and amount are treated as numbers.

## MobX autorun() for Reactive Calculations

For more complex derived state, use MobX `autorun()` directly. This is ideal for the "cart/order" pattern:

### Form setup

```javascript
const fields = [
  'products',
  'products[].name',
  'products[].qty',
  'products[].amount',
  'products[].total',
  'orderTotal',
];

const values = {
  products: [
    { name: 'MacBook Pro', qty: 1, amount: 2499, total: 0 },
    { name: 'AirPods Pro', qty: 2, amount: 249, total: 0 },
  ],
};

const types = {
  'products[].qty': 'number',
  'products[].amount': 'number',
  'products[].total': 'number',
  'orderTotal': 'number',
};

const hooks = {
  onInit(form) {
    if (form.$('products').fields.size === 0) {
      form.$('products').add();
    }
  },
};
```

### The autorun engine

```jsx
import { autorun } from 'mobx';

function CartComponent({ form }) {
  const products = form.$('products');

  useEffect(() => {
    const disposer = autorun(() => {
      const orderTotalField = form.$('orderTotal');
      let grandTotal = 0;

      products.map((item) => {
        const qty = Number(item.$('qty')?.value) || 0;
        const amount = Number(item.$('amount')?.value) || 0;
        const rowTotal = Number((qty * amount).toFixed(2));
        item.$('total')?.set(rowTotal);
        grandTotal += rowTotal;
      });

      orderTotalField.set(Number(grandTotal.toFixed(2)));
    });

    return () => disposer(); // cleanup on unmount
  }, [form, products]);

  // ...
}
```

### Observer components for fine-grained rendering

```jsx
const ProductRow = observer(({ field, onDelete }) => (
  
    
    
    
    € {field.$('total')?.value ?? 0}
    Remove
  
));

const FormComponent = observer(({ form }) => {
  const products = form.$('products');

  return (
    
      {products.map((field) => (
         products.del(field.key)}
        />
      ))}
      Total: € {form.$('orderTotal').value}
       products.add()}>Add Product
    
  );
});
```

## Computed Props vs autorun() — When to Use

| Aspect | Computed Field Prop | autorun() |
|--------|-------------------|-----------|
| **Definition** | In field configuration | In component `useEffect` |
| **Best for** | Simple derived values | Complex multi-field calculations |
| **Nested arrays** | Supported via `computed` path | Full control |
| **Side effects** | No (pure functions) | Yes (set values, call APIs) |
| **Cleanup** | Automatic | Manual (call disposer) |

## Using autorun() for Computed Display

```jsx
const autorunDisposer = autorun(() => {
  const full = `${firstName.value} ${lastName.value}`.trim();
  form.$('fullDisplay').set(full || '(empty)');
  setComputed(full || '(empty)');
});
```

MobX tracks every observable access inside `autorun()` — it re-runs whenever any accessed observable changes.

## Derived Field Props (label, placeholder, disabled)

```javascript
const fields = {
  discountCode: {
    label: ({ form }) =>
      form.$('hasDiscount')?.value ? 'Discount Code' : 'No discount available',
    disabled: ({ form }) =>
      !form.$('hasDiscount')?.value,
    rules: ({ form }) =>
      form.$('hasDiscount')?.value ? 'required|min:3' : '',
  },
  hasDiscount: {
    type: 'checkbox',
    value: false,
  },
};

new Form({ fields }, { options: { strictSelect: false } });
```

## Key Takeaways

1. **Computed Field Props**: Declarative functions in field definitions — best for simple derived values.
2. **`strictSelect: false`**: Required when computed functions access fields before they exist.
3. **autorun()**: Imperative, powerful — ideal for complex multi-field calculations like cart totals.
4. **Nested arrays**: Use the `computed` path for array items (e.g., `products[].total`).
5. **Fine-grained rendering**: Each product row as a separate `observer()` minimizes re-renders.
6. **Cleanup**: `autorun()` returns a disposer — call it on unmount.
7. **Derived props**: `label`, `placeholder`, `disabled`, etc. can also be computed functions.

## Related Skills

- [mobx-react-form-api](../mobx-react-form-api/SKILL.md) — Core API prerequisite
- [mobx-react-form-validation](../mobx-react-form-validation/SKILL.md) — Validation setup
- [mobx-react-form-observers-interceptors](../mobx-react-form-observers-interceptors/SKILL.md) — observe/intercept
- [mobx-react-form-events](../mobx-react-form-events/SKILL.md) — Event hooks

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [foxhound87](https://github.com/foxhound87)
- **Source:** [foxhound87/skills](https://github.com/foxhound87/skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-foxhound87-skills-mobx-react-form-computed
- Seller: https://agentstack.voostack.com/s/foxhound87
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
