A React compatibility layer for Preact
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Data update utilities for managing immutable state transformations safely and efficiently.
Immutable update utility based on MongoDB's query language for safe state modifications.
/**
* Immutably update nested data structures
* @param {any} object - Object to update
* @param {UpdateSpec} spec - Update specification
* @returns {any} New object with updates applied
*/
function update(object, spec);
/**
* Update specification object
*/
interface UpdateSpec {
/** Set a value */
$set?: any;
/** Merge an object (shallow merge) */
$merge?: object;
/** Push items to end of array */
$push?: Array<any>;
/** Add items to beginning of array */
$unshift?: Array<any>;
/** Splice array (remove/insert items) */
$splice?: Array<[number, number, ...any[]]>;
/** Apply function to transform value */
$apply?: (value: any) => any;
/** Toggle boolean value */
$toggle?: Array<string>;
/** Remove items from array by index */
$unset?: Array<string | number>;
/** Nested updates - any key can contain another UpdateSpec */
[key: string]: UpdateSpec | any;
}Usage Examples:
import update from 'preact-compat/lib/update';
// Initial state
const state = {
user: {
name: 'John',
profile: {
age: 30,
preferences: ['music', 'sports']
}
},
items: [1, 2, 3],
settings: {
theme: 'light',
notifications: true
}
};
// Update nested object
const newState1 = update(state, {
user: {
name: { $set: 'Jane' },
profile: {
age: { $set: 31 },
preferences: { $push: ['reading'] }
}
}
});
// Merge objects
const newState2 = update(state, {
settings: { $merge: { theme: 'dark', language: 'en' } }
});
// Array operations
const newState3 = update(state, {
items: { $splice: [[1, 1, 10, 11]] } // Remove 1 item at index 1, insert 10, 11
});
// Apply function transformation
const newState4 = update(state, {
user: {
profile: {
age: { $apply: age => age + 1 }
}
}
});import update from 'preact-compat/lib/update';
class TodoApp extends Component {
state = {
todos: [
{ id: 1, text: 'Learn React', completed: false },
{ id: 2, text: 'Build app', completed: false }
],
filter: 'all'
};
// Add new todo
addTodo = (text) => {
const newTodo = {
id: Date.now(),
text,
completed: false
};
this.setState(update(this.state, {
todos: { $push: [newTodo] }
}));
};
// Toggle todo completion
toggleTodo = (id) => {
const todoIndex = this.state.todos.findIndex(todo => todo.id === id);
this.setState(update(this.state, {
todos: {
[todoIndex]: {
completed: { $apply: completed => !completed }
}
}
}));
};
// Remove todo
removeTodo = (id) => {
const todoIndex = this.state.todos.findIndex(todo => todo.id === id);
this.setState(update(this.state, {
todos: { $splice: [[todoIndex, 1]] }
}));
};
// Update filter
setFilter = (filter) => {
this.setState(update(this.state, {
filter: { $set: filter }
}));
};
// Bulk operations
completeAll = () => {
this.setState(update(this.state, {
todos: { $apply: todos =>
todos.map(todo => ({ ...todo, completed: true }))
}
}));
};
render() {
const { todos, filter } = this.state;
return (
<div>
<input
onKeyPress={(e) => {
if (e.key === 'Enter') {
this.addTodo(e.target.value);
e.target.value = '';
}
}}
placeholder="Add todo..."
/>
<button onClick={this.completeAll}>Complete All</button>
{todos.map(todo => (
<div key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => this.toggleTodo(todo.id)}
/>
<span style={{
textDecoration: todo.completed ? 'line-through' : 'none'
}}>
{todo.text}
</span>
<button onClick={() => this.removeTodo(todo.id)}>Remove</button>
</div>
))}
</div>
);
}
}import update from 'preact-compat/lib/update';
// Complex nested updates
const complexState = {
users: {
byId: {
1: { name: 'John', posts: [10, 20] },
2: { name: 'Jane', posts: [30] }
},
allIds: [1, 2]
},
posts: {
byId: {
10: { title: 'Post 1', likes: 5 },
20: { title: 'Post 2', likes: 3 },
30: { title: 'Post 3', likes: 8 }
},
allIds: [10, 20, 30]
}
};
// Add new user with post
function addUserWithPost(state, user, post) {
return update(state, {
users: {
byId: { $merge: { [user.id]: user } },
allIds: { $push: [user.id] }
},
posts: {
byId: { $merge: { [post.id]: post } },
allIds: { $push: [post.id] }
}
});
}
// Update multiple related entities
function likePost(state, postId, userId) {
return update(state, {
posts: {
byId: {
[postId]: {
likes: { $apply: likes => likes + 1 }
}
}
},
users: {
byId: {
[userId]: {
likedPosts: { $push: [postId] }
}
}
}
});
}
// Conditional updates
function updateUserIfExists(state, userId, updates) {
if (state.users.byId[userId]) {
return update(state, {
users: {
byId: {
[userId]: { $merge: updates }
}
}
});
}
return state;
}// Main import
import update from 'preact-compat/lib/update';
// CommonJS
const update = require('preact-compat/lib/update');interface UpdateSpec {
$set?: any;
$merge?: object;
$push?: Array<any>;
$unshift?: Array<any>;
$splice?: Array<SpliceOperation>;
$apply?: (value: any) => any;
$toggle?: Array<string>;
$unset?: Array<string | number>;
[key: string]: UpdateSpec | any;
}
type SpliceOperation = [number, number, ...any[]];
type UpdateFunction = <T>(object: T, spec: UpdateSpec) => T;Install with Tessl CLI
npx tessl i tessl/npm-preact-compat