import { PureComponent } from 'react'; import counterAutomat from '../automats/counterAutomat.js'; /** * CounterButton — left column. * * HYBRID STATE PATTERN: * - Shared state: `count` comes from counterAutomat. * - Local state: `step` (increment size) and `localClicks` (click counter) * are private to this component. * * 1. Constructor combines direct automat access with local component state. * 2. componentDidMount registers with counterAutomat.subscribe(this). * 3. React's setState shallow-merges updates, so local fields remain untouched * when the automat notifies this component of count updates. */ class CounterButton extends PureComponent { constructor(props) { super(props); // Hybrid initialization: this.state = { // 1. Initialized directly from the automat: count: counterAutomat.state.count, // 2. Component-local state: step: 1, localClicks: 0, }; } componentDidMount() { // Subscriber handling for React lifecycle management this.unsubscribe = counterAutomat.subscribe(this); } componentWillUnmount() { this.unsubscribe(); } handleSetStep = (step) => { // Purely local state update this.setState({ step }); }; handleIncrement = () => { const { step, localClicks } = this.state; // Update local clicks counter this.setState({ localClicks: localClicks + 1 }); // Trigger automat action with local step counterAutomat.actions.increment(step); }; handleDecrement = () => { const { step, localClicks } = this.state; this.setState({ localClicks: localClicks + 1 }); counterAutomat.actions.decrement(step); }; handleReset = () => { const { localClicks } = this.state; this.setState({ localClicks: localClicks + 1 }); counterAutomat.actions.reset(); }; render() { const { count, step, localClicks } = this.state; return (
{`// 1. Instantiate the automat outside React:
const counterAutomat = new Automat(
{ count: 0 },
{
increment(step = 1) {
counterAutomat.setState({ count: counterAutomat.state.count + step });
},
decrement(step = 1) {
counterAutomat.setState({ count: counterAutomat.state.count - step });
},
}
);
// 2. PureComponent with hybrid state:
class CounterButton extends PureComponent {
constructor(props) {
super(props);
this.state = {
count: counterAutomat.state.count, // ← from automat
step: 1, // ← component-local
localClicks: 0, // ← component-local
};
}
componentDidMount() {
this.unsub = counterAutomat.subscribe(this);
}
componentWillUnmount() {
this.unsub();
}
}`}