Computed Values

Computed values in QuantaJS are reactive derived state that automatically update when their dependencies change. They're perfect for calculations, filtering, and transforming data.

Creating Computed Values

Use the computed function to create reactive computed values:

import { reactive, computed } from '@quantajs/core';

const state = reactive({
  count: 0,
  price: 10,
});

const doubleCount = computed(() => state.count * 2);
const totalPrice = computed(() => state.count * state.price);

console.log(doubleCount.value); // 0
console.log(totalPrice.value); // 0

state.count = 5;
console.log(doubleCount.value); // 10
console.log(totalPrice.value); // 50

Computed Values in Stores

Stores have built-in support for computed values through getters:

import { createStore } from '@quantajs/core';

const todoStore = createStore('todos', {
  state: () => ({
    todos: [
      { id: 1, text: 'Learn QuantaJS', done: false },
      { id: 2, text: 'Build an app', done: true },
      { id: 3, text: 'Deploy', done: false },
    ],
  }),
  getters: {
    totalTodos: (state) => state.todos.length,
    completedTodos: (state) => state.todos.filter(todo => todo.done),
    pendingTodos: (state) => state.todos.filter(todo => !todo.done),
    completionRate: (state) => {
      if (state.todos.length === 0) return 0;
      return (state.todos.filter(todo => todo.done).length / state.todos.length) * 100;
    },
  },
  actions: {
    addTodo(text) {
      this.todos.push({
        id: Date.now(),
        text,
        done: false,
      });
    },
    toggleTodo(id) {
      const todo = this.todos.find(t => t.id === id);
      if (todo) todo.done = !todo.done;
    },
  },
});

console.log(todoStore.totalTodos); // 3
console.log(todoStore.completedTodos.length); // 1
console.log(todoStore.pendingTodos.length); // 2
console.log(todoStore.completionRate); // 33.33...

todoStore.addTodo('New task');
console.log(todoStore.totalTodos); // 4
console.log(todoStore.completionRate); // 25...

Complex Computations

Computed values can handle complex logic and multiple dependencies:

const userStore = createStore('user', {
  state: () => ({
    users: [
      { id: 1, name: 'Alice', age: 25, role: 'admin' },
      { id: 2, name: 'Bob', age: 30, role: 'user' },
      { id: 3, name: 'Charlie', age: 35, role: 'admin' },
    ],
    filter: {
      minAge: 0,
      maxAge: 100,
      role: 'all',
    },
  }),
  getters: {
    filteredUsers: (state) => {
      return state.users.filter(user => {
        const ageMatch = user.age >= state.filter.minAge && user.age <= state.filter.maxAge;
        const roleMatch = state.filter.role === 'all' || user.role === state.filter.role;
        return ageMatch && roleMatch;
      });
    },
    averageAge: (state) => {
      if (state.users.length === 0) return 0;
      const total = state.users.reduce((sum, user) => sum + user.age, 0);
      return Math.round(total / state.users.length);
    },
    userStats: (state) => {
      const admins = state.users.filter(user => user.role === 'admin').length;
      const regularUsers = state.users.filter(user => user.role === 'user').length;
      return { admins, regularUsers, total: state.users.length };
    },
  },
  actions: {
    updateFilter(filter) {
      Object.assign(this.filter, filter);
    },
  },
});

console.log(userStore.filteredUsers.length); // 3
console.log(userStore.averageAge); // 30
console.log(userStore.userStats); // { admins: 2, regularUsers: 1, total: 3 }

userStore.updateFilter({ minAge: 30, role: 'admin' });
console.log(userStore.filteredUsers.length); // 1 (only Charlie)

Performance Benefits

Computed values are cached and only recalculate when dependencies change:

const expensiveStore = createStore('expensive', {
  state: () => ({
    items: Array.from({ length: 1000 }, (_, i) => ({ id: i, value: Math.random() })),
  }),
  getters: {
    // This expensive calculation only runs when items change
    expensiveCalculation: (state) => {
      console.log('Computing expensive value...');
      return state.items
        .map(item => item.value * 2)
        .reduce((sum, val) => sum + val, 0);
    },
  },
});

// First access - computes the value
console.log(expensiveStore.expensiveCalculation);

// Second access - uses cached value (no computation)
console.log(expensiveStore.expensiveCalculation);

// Only when items change does it recompute
expensiveStore.items.push({ id: 1000, value: 0.5 });
console.log(expensiveStore.expensiveCalculation); // Recomputes

Learn More