Sync React Component State Without Heavy Libraries: Custom Hook & Pub‑Sub
This article explains how to synchronize state across distant React components without relying on heavy libraries, using a custom hook and a publish‑subscribe model, and discusses optimizations such as avoiding redundant updates and incorporating a simple reducer for efficient change detection.
Background
When developing frontend features, we often need to synchronize internal state across distant components. For example, a ThemeSwitch component changes its color state and wants to update other components for a live theme preview.
Typically Redux is used, but two questions arise: 1) Can we sync state simply without third‑party libraries? 2) How do state‑management libraries work internally?
Just want to sync a state—can it be done without adding a library?
What is the internal implementation principle of state‑management libraries?
Problem Analysis
Two analysis approaches exist: 0‑1 (run code step by step) and 1‑0 (start from the desired result). We adopt the 1‑0 method.
1. Notification Sync
When ThemeSwitch changes the theme via setColor(newColor), we simply need to notify other components to execute the same setColor(newColor) to update their state.
2. How to Notify?
Collect the setColor calls and invoke them—a classic publish‑subscribe model. Define a custom hook useColorState as a controller to maintain subscription‑publish functionality.
Solution
Implement a custom hook that intercepts component state definitions to bind subscription relationships and provide publish‑subscribe capability.
1. Custom Hook
export default function useColorState() {
const [color, setColor] = useState();
return [color, setColor];
}2. Publish‑Subscribe Model
class ColorChanger {
constructor() {
this.color = 'orange';
this.callBacks = [];
}
subscribe(cb) {
this.callBacks.push(cb);
}
publish() {
this.callBacks.forEach(cb => cb(this.color));
}
}3. Subscription
Initialize subscription and internal state.
let colorChanger;
function useColorState() {
// ...
useEffect(() => {
colorChanger = colorChanger || new ColorChanger();
colorChanger.subscribe(setColor);
setColor(colorChanger.color);
}, []);
// ...
}4. Publish
The hook returns a changeColor function that updates the ColorChanger and triggers publish.
function useColorState() {
// ...
const changeColor = (val) => {
colorChanger.setColor(val);
};
return [color, changeColor];
}
class ColorChanger {
// ...
setColor(color) {
this.color = color;
this.publish();
}
}5. Unsubscribe
When a component unmounts, remove its setColor from the callbacks.
class ColorChanger {
// ...
unsubscribe(cb) {
this.callBacks.splice(this.callBacks.indexOf(cb), 1);
}
}
function useColorState() {
useEffect(() => {
// ...
return () => {
colorChanger.unsubscribe(setColor);
};
}, []);
}Optimization
Small optimization: avoid publishing when setColor receives the same color, as publishing is costly.
setColor(color) {
if (this.color === color) return;
// ...
}2. Reducer
Redux uses reducers to efficiently compare old and new state. For a simple string color we can implement a reducer.
Define a reducer and integrate it into useColorState.
const newState = reducer(oldState, action);
function colorReducer(state = { color: 'orange' }, action) {
return action.color === state.color ? state : { color: action.color };
}
function useColorState(colorReducer) {
colorChanger = colorChanger || new ColorChanger(colorReducer);
// ...
}
class ColorChanger {
setColor(action) {
const newState = this.colorReducer(this.state, action);
// ...
}
}Further optimizations include wrapping changeColor with useCallback, queuing publishes, etc.
Conclusion
The article discusses common component state synchronization in web development and presents a simple solution using a custom hook and publish‑subscribe pattern, with notes on optimization and reducer usage for efficient change detection.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
