Inconsistent State Synchronization with Custom useLocalStorage Hook in React

I’m encountering an issue with state synchronization in a React application using a custom useLocalStorage hook. The App component correctly logs changes to the counter state, while another hook trying to access the same state doesn’t log these changes, even though the state is supposed to be shared via local storage.

codesandbox here

Here’s the code:

import { useState, useEffect } from "react";

const useLocalStorage = (key, initialValue) => {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error("Failed to read from localStorage", error);
      return initialValue;
    }
  });

  const setValue = (value) => {
    try {
      const valueToStore =
        value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error("Failed to write to localStorage", error);
    }
  };

  useEffect(() => {
    const handleStorageChange = (event) => {
      if (event.key === key && event.newValue) {
        setStoredValue(JSON.parse(event.newValue));
      }
    };

    window.addEventListener("storage", handleStorageChange);
    return () => window.removeEventListener("storage", handleStorageChange);
  }, [key]);

  return [storedValue, setValue];
};

const useCounter = () => {
  const [counter, setCounter] = useLocalStorage("counter", 0);

  const incrementCounter = () => setCounter((prev) => (prev += 1));

  return { counter, incrementCounter };
};

const useInput = () => {
  const [input, setInput] = useState("");
  const { counter } = useCounter();

  useEffect(() => {
    console.log("useEffect in useInput"); // this does not run as I type
  }, [counter]);

  return { input, setInput };
};

export default function App() {
  const { input, setInput } = useInput();
  const { counter, incrementCounter } = useCounter();

  useEffect(() => {
    console.log("useEffect in App"); // this runs as I type
  }, [counter]);

  const handleInput = (value) => {
    incrementCounter();
    setInput(value);
  };

  return <input onChange={(e) => handleInput(e.target.value)} value={input} />;
}

The App component correctly logs changes to the counter state, but the useEffect inside the useInput hook does not log these changes. I expected both useEffect hooks to be triggered when counter is incremented. Why is this happening, and how can I ensure the state is consistently shared and updated across components?