Understanding the .subscribe()
Method
What is .subscribe()
and Why Do We Need It?
The .subscribe()
method lets you listen to state changes manually. It gives you full control over when to start listening and when to stop listening. This is different from .watch()
which automatically manages subscriptions for you.
Simple Example
tsx
import { signify } from "react-signify";
const sCount = signify(0);
function Component() {
useEffect(() => {
// Start listening to changes
const { unsubscribe } = sCount.subscribe((count) => {
console.log("Count is now:", count);
});
// Stop listening when component unmounts
return () => {
unsubscribe();
};
}, []);
return <div>Component</div>;
}
How .subscribe()
Works
It's very simple:
- Call
.subscribe()
with a callback function - Get back an
unsubscribe
function - Use
unsubscribe()
to stop listening
tsx
// Step 1: Create a signify state
const sMessage = signify("Hello");
// Step 2: Subscribe to changes
const { unsubscribe } = sMessage.subscribe((message) => {
console.log("Message:", message);
});
// Step 3: Change the state (callback will run)
sMessage.set("World"); // Console: "Message: World"
// Step 4: Stop listening
unsubscribe();
// Step 5: Change again (callback won't run)
sMessage.set("Goodbye"); // Nothing logged
When to Use .subscribe()
vs .watch()
Use .subscribe() when: | Use .watch() when: |
---|---|
You need manual control | You want automatic management |
Using with useEffect | Using directly in component |
Conditional listening | Always listening |
Common Use Cases
1. Basic Logging
Listen to state changes and log them:
tsx
const sUser = signify({ name: "John", age: 25 });
function App() {
useEffect(() => {
const { unsubscribe } = sUser.subscribe((user) => {
console.log("User updated:", user);
});
return unsubscribe;
}, []);
return <div>App</div>;
}
2. Conditional Listening
Start and stop listening based on user actions:
tsx
const sMessages = signify([]);
function ChatApp() {
const [isListening, setIsListening] = useState(false);
const subscriptionRef = useRef(null);
const toggleListening = () => {
if (isListening) {
// Stop listening
if (subscriptionRef.current) {
subscriptionRef.current.unsubscribe();
subscriptionRef.current = null;
}
} else {
// Start listening
subscriptionRef.current = sMessages.subscribe((messages) => {
console.log("New messages:", messages);
});
}
setIsListening(!isListening);
};
// Cleanup on unmount
useEffect(() => {
return () => {
if (subscriptionRef.current) {
subscriptionRef.current.unsubscribe();
}
};
}, []);
return (
<div>
<button onClick={toggleListening}>
{isListening ? "Stop" : "Start"} Listening
</button>
</div>
);
}
3. Listening to Multiple States
Listen to different states in one component:
tsx
const sCount = signify(0);
const sName = signify("John");
function MultiListener() {
useEffect(() => {
// Listen to count changes
const countSub = sCount.subscribe((count) => {
console.log("Count:", count);
});
// Listen to name changes
const nameSub = sName.subscribe((name) => {
console.log("Name:", name);
});
// Cleanup both subscriptions
return () => {
countSub.unsubscribe();
nameSub.unsubscribe();
};
}, []);
return <div>Multi Listener</div>;
}
4. Using Outside React Components
You can use .subscribe()
anywhere in your code, not just in React components:
tsx
const sSettings = signify({ theme: "light", language: "en" });
// Listen to settings changes outside of React
const { unsubscribe } = sSettings.subscribe((settings) => {
// Update localStorage when settings change
localStorage.setItem("settings", JSON.stringify(settings));
console.log("Settings saved:", settings);
});
// Later, when you don't need it anymore
// unsubscribe();
Best Practices
✅ Always Unsubscribe
tsx
function Component() {
useEffect(() => {
const { unsubscribe } = sData.subscribe((data) => {
console.log(data);
});
// IMPORTANT: Always clean up!
return () => {
unsubscribe();
};
}, []);
return <div>Component</div>;
}
✅ Handle Errors Safely
tsx
function Component() {
useEffect(() => {
const { unsubscribe } = sData.subscribe((data) => {
try {
// Your logic here
processData(data);
} catch (error) {
console.error("Error:", error);
}
});
return unsubscribe;
}, []);
return <div>Component</div>;
}
❌ Don't Create Subscriptions in Render
tsx
// ❌ Wrong - creates new subscription every render
function BadComponent() {
const { unsubscribe } = sData.subscribe((data) => {
console.log(data);
});
return <div>Bad</div>;
}
// ✅ Correct - create in useEffect
function GoodComponent() {
useEffect(() => {
const { unsubscribe } = sData.subscribe((data) => {
console.log(data);
});
return unsubscribe;
}, []);
return <div>Good</div>;
}
TypeScript Support
React Signify works great with TypeScript:
tsx
interface User {
name: string;
age: number;
}
const sUser = signify<User>({ name: "John", age: 25 });
function Component() {
useEffect(() => {
const { unsubscribe } = sUser.subscribe((user) => {
// TypeScript knows 'user' is type User
console.log(`${user.name} is ${user.age} years old`);
});
return unsubscribe;
}, []);
return <div>Component</div>;
}
Summary
The .subscribe()
method gives you manual control over listening to state changes in React Signify.
Key Points:
- Call
.subscribe(callback)
to start listening - Get back
{ unsubscribe }
to stop listening - Always call
unsubscribe()
in cleanup - Use in
useEffect
for React components
The Basic Pattern:
tsx
function Component() {
useEffect(() => {
const { unsubscribe } = signifyState.subscribe((value) => {
console.log("New value:", value);
});
return () => {
unsubscribe(); // Always clean up!
};
}, []);
return <div>Component</div>;
}
When to Use:
Use .subscribe() when: | Use .watch() when: |
---|---|
You need manual control | You want automatic management |
Using with useEffect | Using directly in component |
Conditional listening | Always listening |
Remember: Always unsubscribe to prevent memory leaks!