Observer (наблюдатель) — это поведенческий паттерн проектирования, который позволяет объектам оповещать другие объекты об изменениях своего состояния. В контексте Preact данный паттерн применяется для организации реактивного взаимодействия компонентов и управления состоянием, особенно в случаях, когда несколько компонентов зависят от одних и тех же данных.
Паттерн Observer состоит из двух ключевых ролей:
Классическая схема работы: субъект изменяет своё состояние и вызывает метод уведомления всех подписанных наблюдателей. Наблюдатели выполняют собственную логику обновления.
Preact не включает встроенный Observer, однако реактивное поведение
можно организовать с использованием хуков, таких как
useState, useReducer и useEffect,
или сторонних библиотек, реализующих реактивное состояние (например,
rxjs, valtio, mobx).
import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
class Subject {
constructor() {
this.observers = [];
this.state = 0;
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
setState(newState) {
this.state = newState;
this.notify();
}
notify() {
this.observers.forEach(observer => observer(this.state));
}
}
const Counter = ({ subject }) => {
const [count, setCount] = useState(subject.state);
useEffect(() => {
const observer = (newState) => setCount(newState);
subject.subscribe(observer);
return () => subject.unsubscribe(observer);
}, [subject]);
return (
<div>
<p>Count: {count}</p>
<button onCl ick={() => subject.setState(subject.state + 1)}>Increment</button>
</div>
);
};
// Использование
const subject = new Subject();
const App = () => (
<div>
<Counter subject={subject} />
<Counter subject={subject} />
</div>
);
В этом примере два компонента Counter подписаны на один
и тот же subject. При изменении состояния
subject оба компонента обновляют отображение
автоматически.
Паттерн Observer в Preact органично сочетается с хуками:
useState для хранения локального состояния.useEffect для подписки и отписки от изменений.useReducer для управления сложными состояниями с
реактивной логикой.Пример использования useReducer для управления
глобальным состоянием с Observer:
import { h } from 'preact';
import { useReducer, useEffect } from 'preact/hooks';
const initialState = { count: 0 };
const subject = {
observers: [],
state: initialState,
subscribe(obs) { this.observers.push(obs); },
unsubscribe(obs) { this.observers = this.observers.filter(o => o !== obs); },
notify() { this.observers.forEach(obs => obs(this.state)); },
dispatch(action) {
switch(action.type) {
case 'increment': this.state = { count: this.state.count + 1 }; break;
case 'decrement': this.state = { count: this.state.count - 1 }; break;
}
this.notify();
}
};
const Counter = () => {
const [state, setState] = useReducer((_, newState) => newState, subject.state);
useEffect(() => {
const observer = (newState) => setState(newState);
subject.subscribe(observer);
return () => subject.unsubscribe(observer);
}, []);
return (
<div>
<p>Count: {state.count}</p>
<button onCl ick={() => subject.dispatch({ type: 'increment' })}>+</button>
<button onCl ick={() => subject.dispatch({ type: 'decrement' })}>-</button>
</div>
);
};
useEffect.