Skip to content

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:

  1. Call .subscribe() with a callback function
  2. Get back an unsubscribe function
  3. 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 controlYou want automatic management
Using with useEffectUsing directly in component
Conditional listeningAlways 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 controlYou want automatic management
Using with useEffectUsing directly in component
Conditional listeningAlways listening

Remember: Always unsubscribe to prevent memory leaks!

Released under the MIT License.