A stateful component owns data that can change while it is in use. Each instance has its own state and lifecycle, and its view changes when that state changes. This avoids keeping every piece of state and every reducer at the application level: a change can re-render the responsible component rather than the whole application. section 9.1 section 9.0
A small implementation separates four responsibilities:
- Define a component class with a render() method that returns its virtual DOM. A defineComponent() factory accepts the component-specific render function and returns a class that can be instantiated. section 9.2
- Create state for each instance in its constructor. A state(props) function can use incoming props to choose an initial value; if no state function is supplied, the initial state is an empty object. section 9.3
- Mount the rendered view into a DOM host and unmount it when finished. Track whether the instance is mounted so mounting twice or unmounting too early raises an error. section 9.2
- Change state through updateState(), not by directly assigning to state. The method updates the state and patches the component’s view; direct assignment would not tell the component to refresh. section 9.1.1 section 9.4
A counter with its own starting value
A counter can define state(props) to return { count: props.initialCount ?? 0 }. Creating it with { initialCount: 10 } gives that instance a starting count of 10. Another instance can start at the default of 0; each then maintains its own state. section 9.3 section 9.1
Listing 9.3 Adding the state() method (component.js)
export function defineComponent({ render, state }) { #1
class Component {
#isMounted = false
#vdom = null
#hostEl = null
constructor(props = {}) {
this.props = props #2
this.state = state ? state(props) : {} #3
}
render() {
return render()
}
mount(hostEl, index = null) {
// --snip-- //
}
unmount() {
// --snip-- //
}
}
return Component
}
The constructor shows where incoming props and per-instance state are stored; the render, mount, and unmount methods remain part of the component class. section 9.3
State and props have different jobs: state is maintained internally, while props arrive from a parent. A class is one way to implement this pattern, not a requirement of every framework: React also has stateful functional components using useState(). In a component hierarchy, the application can receive just a root component instead of a global state object and reducers. section 9.1.1 section 9.1 section 12.4
