Skip to content

Sponsor

Sponsor

collection.add(item) - Add Item to Collection

Quick Start (30 seconds)

javascript
const todos = createCollection([
  { id: 1, text: 'Buy milk', done: false }
]);

// Add a single item
todos.add({ id: 2, text: 'Walk dog', done: false });

console.log(todos.items);
// [
//   { id: 1, text: 'Buy milk', done: false },
//   { id: 2, text: 'Walk dog', done: false }
// ]

// Method chaining (returns this)
todos
  .add({ id: 3, text: 'Clean room', done: false })
  .add({ id: 4, text: 'Cook dinner', done: false });

console.log(todos.length);  // 4

// Reactive updates ✨
effect(() => {
  document.getElementById('count').textContent = `${todos.length} tasks`;
});

todos.add({ id: 5, text: 'Study', done: false });
// UI auto-updates: "5 tasks"

What just happened? You added items to a collection, and the UI updated automatically!

What is collection.add(item)?

add(item) is a method that appends a new item to the end of a reactive collection.

Simply put: it's a clean way to grow your collection by adding items one at a time.

Think of it as dropping a new item into a box - it goes to the bottom of the pile.

Syntax

javascript
collection.add(item)

Parameters:

  • item (any) - The item to add. Can be any type (object, string, number, etc.)

Returns: The collection itself (for chaining)

Why Does This Exist?

Two Approaches to Adding Items to Collections

The Reactive library offers flexible ways to add items to collections, each suited to different coding preferences.

Direct Array Manipulation

When you prefer standard JavaScript array methods and want to work with familiar patterns:

javascript
const todos = createCollection([]);

// Use standard array push
todos.items.push({ text: 'Task 1' });

// Or use spread syntax
todos.items = [...todos.items, { text: 'Task 2' }];

// Multiple additions
todos.items.push({ text: 'Task 3' });
todos.items.push({ text: 'Task 4' });

This approach is great when you need: ✅ Standard JavaScript array API ✅ Familiar push/spread patterns ✅ Direct access to array methods ✅ Compatibility with existing array code

When Expressive Collection Methods Fit Your Style

In scenarios where you want semantic, chainable operations that express intent clearly, add() provides a more direct approach:

javascript
const todos = createCollection([]);

// Semantic method name
todos.add({ text: 'Task 1' });

// Method chaining for multiple additions
todos
  .add({ text: 'Task 2' })
  .add({ text: 'Task 3' })
  .add({ text: 'Task 4' });

// Clear intent: "add item to collection"

This method is especially useful when:

add() Flow:
┌──────────────────┐
│ add(item)        │
└────────┬─────────┘


   Appends to items


   Returns collection


  ✅ Chainable operations

Where add() shines:Semantic clarity - Method name expresses intent ✅ Chainable operations - Returns collection for fluent API ✅ Consistent with collection API - Matches remove(), update(), etc. ✅ Expressive code - Reads like natural language ✅ Clean syntax - One method for adding items

The Choice is Yours:

  • Use todos.items.push() when you prefer standard array methods
  • Use todos.add() when you want semantic, chainable collection operations
  • Both approaches work with reactive collections

Benefits of the add approach:Clear intent - add() clearly communicates the operation ✅ Method chaining - Returns collection for fluent operations ✅ Collection-focused - Part of a consistent collection API ✅ Readable code - Expressive method names improve clarity ✅ Consistent pattern - Matches other collection methods like remove(), update()

Mental Model

Think of a collection as a container you drop items into:

Before add()             After add(item)
┌─────────────┐         ┌─────────────┐
│  Items:     │         │  Items:     │
│  [A]        │  add(B) │  [A]        │
│  [B]        │  ────→  │  [B]        │
│             │         │  [C] ← NEW  │
└─────────────┘         └─────────────┘

Key Insight: Items always go to the end (like push).

How Does It Works

The complete flow when you call add():

todos.add({ text: 'New task' })
        |

this.items.push(item)
        |

Array changes
        |

Reactivity triggered
        |

Effects re-run
        |

UI updates
        |

return this (for chaining)

Implementation

javascript
// From 03_dh-reactive-collections.js
add(item) {
  this.items.push(item);
  return this;
}

Simple and effective:

  • Uses native push() to append
  • With Module 02, push() is patched for reactivity
  • Returns this for chaining

Basic Usage

Example 1: Add Todo Items

javascript
const todos = createCollection([]);

todos.add({ id: 1, text: 'Buy groceries', done: false });
todos.add({ id: 2, text: 'Call mom', done: false });
todos.add({ id: 3, text: 'Finish report', done: false });

console.log(todos.length);  // 3

Example 2: Method Chaining

javascript
const cart = createCollection([]);

cart
  .add({ product: 'Laptop', price: 999, qty: 1 })
  .add({ product: 'Mouse', price: 25, qty: 2 })
  .add({ product: 'Keyboard', price: 75, qty: 1 });

console.log(cart.length);  // 3

Example 3: Different Data Types

javascript
// Numbers
const numbers = createCollection([]);
numbers.add(1).add(2).add(3);

// Strings
const tags = createCollection([]);
tags.add('javascript').add('react').add('vue');

// Mixed
const mixed = createCollection([]);
mixed.add(42).add('hello').add({ key: 'value' });

Real-World Examples

Example 1: User Input Handler

javascript
const messages = createCollection([]);

function sendMessage(text) {
  messages.add({
    id: Date.now(),
    text,
    user: currentUser.name,
    timestamp: new Date()
  });
}

// User sends messages
sendMessage('Hello!');
sendMessage('How are you?');

// Reactive UI update
effect(() => {
  const container = document.getElementById('messages');
  container.innerHTML = messages.items.map(m => `
    <div class="message">
      <strong>${m.user}:</strong> ${m.text}
    </div>
  `).join('');
});

Example 2: Auto-Generated IDs

javascript
const items = createCollection([]);

function addItem(data) {
  const id = (items.last?.id || 0) + 1;  // Auto-increment

  items.add({
    id,
    ...data,
    createdAt: Date.now()
  });

  return id;
}

const id1 = addItem({ name: 'Item 1' });  // ID: 1
const id2 = addItem({ name: 'Item 2' });  // ID: 2
const id3 = addItem({ name: 'Item 3' });  // ID: 3

console.log(items.items);
// [
//   { id: 1, name: 'Item 1', createdAt: ... },
//   { id: 2, name: 'Item 2', createdAt: ... },
//   { id: 3, name: 'Item 3', createdAt: ... }
// ]

Example 3: Add with Validation

javascript
const products = createCollection([]);

function addProduct(product) {
  // Validation
  if (!product.name) {
    throw new Error('Product name required');
  }

  if (product.price <= 0) {
    throw new Error('Price must be positive');
  }

  // Add if valid
  products.add({
    ...product,
    addedAt: Date.now()
  });

  console.log(`Added: ${product.name}`);
}

// Usage
addProduct({ name: 'Widget', price: 10 });  // ✅ Success
addProduct({ name: 'Gadget', price: -5 });  // ❌ Error thrown

Example 4: Add from API Response

javascript
const users = createCollection([]);

async function fetchUsers() {
  const response = await fetch('/api/users');
  const data = await response.json();

  // Add each user
  data.forEach(user => {
    users.add(user);
  });

  console.log(`Loaded ${users.length} users`);
}

// Or more efficient for bulk:
async function fetchUsersBatch() {
  const response = await fetch('/api/users');
  const data = await response.json();

  // Replace entire array (single reactivity trigger)
  users.items = data;
}

Example 5: Add with Duplicate Check

javascript
const tags = createCollection([]);

function addTag(tag) {
  // Check for duplicates
  const exists = tags.items.some(t => t === tag);

  if (!exists) {
    tags.add(tag);
    console.log(`Added tag: ${tag}`);
  } else {
    console.log(`Tag already exists: ${tag}`);
  }
}

addTag('javascript');  // "Added tag: javascript"
addTag('react');       // "Added tag: react"
addTag('javascript');  // "Tag already exists: javascript"

console.log(tags.items);  // ['javascript', 'react']

Example 6: Add to Sorted Collection

javascript
const scores = createCollection([]);

function addScore(score) {
  scores.add(score);
  scores.sort((a, b) => b - a);  // Keep sorted descending
}

addScore(100);
addScore(250);
addScore(180);
addScore(220);

console.log(scores.items);  // [250, 220, 180, 100]

Example 7: Add with Max Limit

javascript
const MAX_ITEMS = 5;
const recentItems = createCollection([]);

function addRecent(item) {
  recentItems.add(item);

  // Remove oldest if over limit
  if (recentItems.length > MAX_ITEMS) {
    recentItems.shift();  // Remove first item
  }
}

// Add 6 items
addRecent('A');
addRecent('B');
addRecent('C');
addRecent('D');
addRecent('E');
addRecent('F');  // 'A' is removed

console.log(recentItems.items);  // ['B', 'C', 'D', 'E', 'F']

Example 8: Add with Notification

javascript
const notifications = createCollection([]);

// Show toast when new notification added
effect(() => {
  if (notifications.length > 0) {
    const latest = notifications.last;
    showToast(latest.message, latest.type);
  }
});

function notify(message, type = 'info') {
  notifications.add({
    id: Date.now(),
    message,
    type,
    timestamp: new Date()
  });
}

notify('File saved successfully', 'success');
notify('Connection lost', 'error');

Example 9: Batch Add with Loop

javascript
const numbers = createCollection([]);

// Add multiple items
for (let i = 1; i <= 10; i++) {
  numbers.add(i * 10);
}

console.log(numbers.items);
// [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

// More efficient with batch
batch(() => {
  for (let i = 1; i <= 100; i++) {
    numbers.add(i);
  }
}); // Only triggers reactivity once

Example 10: Conditional Add

javascript
const activeUsers = createCollection([]);

function updateUserStatus(user) {
  const FIVE_MINUTES = 5 * 60 * 1000;
  const isActive = user.lastSeen > Date.now() - FIVE_MINUTES;

  if (isActive) {
    activeUsers.add(user);
  }
}

// Process users
users.forEach(updateUserStatus);

console.log(`${activeUsers.length} active users`);

Common Patterns

Pattern 1: Add and Return Item

javascript
function addTodo(text) {
  const todo = {
    id: Date.now(),
    text,
    done: false,
    createdAt: new Date()
  };

  todos.add(todo);
  return todo;  // Return the item, not collection
}

const newTodo = addTodo('Learn patterns');
console.log(newTodo.id);

Pattern 2: Bulk Add Helper

javascript
function addMultiple(items) {
  items.forEach(item => collection.add(item));
}

// Usage
addMultiple([
  { name: 'Item 1' },
  { name: 'Item 2' },
  { name: 'Item 3' }
]);

// More efficient alternative
function addMultipleBatch(newItems) {
  collection.items = [...collection.items, ...newItems];
}

Pattern 3: Add Unique Items

javascript
function addUnique(item, keyFn = x => x) {
  const exists = collection.items.some(x => 
    keyFn(x) === keyFn(item)
  );
  
  if (!exists) {
    collection.add(item);
    return true;
  }
  
  return false;
}

// Usage
addUnique({ id: 1, name: 'John' }, x => x.id);

Pattern 4: Add with Limit

javascript
function addWithLimit(item, max = 100) {
  if (collection.length >= max) {
    collection.remove(collection.first);  // Remove oldest
  }
  collection.add(item);
}

Pattern 5: Add and Sort

javascript
function addSorted(item, compareFn) {
  collection.add(item);
  collection.sort(compareFn);
}

// Usage
addSorted({ priority: 3, task: 'Medium' }, 
  (a, b) => b.priority - a.priority
);

Important Notes

1. Returns Collection, Not Item

javascript
// ❌ Wrong: add() returns collection, not item
const newTodo = todos.add({ text: 'Task' });
console.log(newTodo.text);  // Error!

// ✅ Correct: access separately
const item = { text: 'Task' };
todos.add(item);
console.log(item.text);  // 'Task'

// ✅ Or get from collection
todos.add({ text: 'Task' });
console.log(todos.last.text);  // 'Task'

2. One Item at a Time

javascript
// ❌ Wrong: only first arg used
items.add(1, 2, 3);  // Only adds 1

// ✅ Correct: chain or loop
items.add(1).add(2).add(3);

[1, 2, 3].forEach(n => items.add(n));

3. Stores Reference, Not Copy

javascript
const todo = { id: 1, text: 'Task', done: false };
todos.add(todo);

// Mutating original affects collection
todo.done = true;
console.log(todos.items[0].done);  // true

// Clone if needed
todos.add({ ...todo });  // Shallow copy

4. Don't Use in Effects

javascript
// ❌ Wrong: infinite loop!
effect(() => {
  items.add('new');  // Triggers effect → adds → triggers → ...
});

// ✅ Correct: add outside
items.add('new');

effect(() => {
  console.log('Count:', items.length);  // Read only
});

Performance Considerations

Add is O(1) - Very Fast

javascript
// Constant time operation
collection.add(item);  // O(1)

Bulk Operations

javascript
// Slower: N reactivity triggers
for (let i = 0; i < 1000; i++) {
  items.add(i);
}

// Faster: 1 reactivity trigger
items.items = [...items.items, ...Array(1000).fill(0).map((_, i) => i)];

// Or use batch
batch(() => {
  for (let i = 0; i < 1000; i++) {
    items.add(i);
  }
}); // Only 1 trigger

When to Use

Use add() For:

Single items - Adding one at a time
Method chaining - Fluent API
User input - Forms, chat, events
Event logging - Activity tracking
Dynamic lists - Growing collections

Don't Use For:

Bulk adding - Hundreds of items (use direct assignment)
Inside effects - Creates infinite loops
Need return value - Returns collection, not item

Summary

What is collection.add(item)?
A method that appends a new item to the end of a reactive collection.

Why use it?

  • ✅ Clean, semantic API
  • ✅ Method chaining support
  • ✅ Automatic reactivity
  • ✅ Clear intent
  • ✅ O(1) performance

Key Takeaway:

Direct push()           add() method
      |                      |
Verbose                 Clean API
      |                      |
No chaining            Chainable
      |                      |
Array method           Collection method ✅

One-Line Rule: Use add() to append items with a clean, chainable API.

Best Practices:

  • Use add() for single items
  • Chain multiple calls for fluent code
  • Use batch for many items
  • Don't mutate items after adding
  • Validate before adding
  • Avoid using in effects

Remember: add() makes growing collections simple and reactive! 🎉