SvenJS 3

State

setState replaces state. It does not merge. That is the 2.x contract.

this.setState({ clicks: this.state.clicks + 1 });
this.setState((s) => ({ ...s, clicks: s.clicks + 1 }));

Several setState calls in one event are batched into a single microtask patch.

In development the new state is structuredCloned and plain objects/arrays are deep-frozen. Mutating this.state.clicks++ throws. Production assigns the next value as-is — treat it as immutable.

Map, Set, Date, and typed arrays are allowed and cloned, but they are not mutation-proof after freeze. Cyclic structures are supported. Functions and DOM nodes throw TypeError: SvenJS: state must be structured-cloneable and leave the previous state in place.

Development diagnostics live in the published svenjs.dev.js / svenjs.iife.dev.js builds. NODE_ENV=development cannot restore code that was already stripped from the production file. Bundlers should honor the package development export condition; a script tag must load the .dev. file explicitly.

initialState may be a value or a factory that receives props. A factory is useful when each mount needs state derived from its own props, and keeps server rendering and hydration deterministic.

const Counter = create({
  initialState: (props) => ({ count: props.start ?? 0 }),
  render() {
    return <button>{this.state.count}</button>;
  },
});

Pass a full object. If you need fields from the previous state, copy them — or use the updater form.