storage 變化監聽

結論先講

想在同一網頁監聽快取的變化,請使用 CustomEvent

問題

事情是這樣的。電商網站,不是都有購物車保存商品的功能嗎?按下商品,右上角的購物車圖標,就會出現一個數字,像這樣……

好的,那麼怎做呢?每個網站都不一樣,但基本上,都要用到瀏覽器快取技術。不管那是 cookie, localStorage, sessionStorage……

問題來了:如何監聽快取的數值變化呢?

探索:DOM 操作流

如果你是用 DOM 操作流的思路,那答案就是:

  1. 選取購物車 DOM。
  2. 修改該 DOM 的數值。

也就是這樣:

const dom = document.querySelector(".shopcart");
const value = "foobar";

localStorage.setItem("shopcart", value);
dom.innerText = value;

但如果你用能切分組件、自行操作 DOM 的框架或函式庫,比方說 React, Vue 這種的話,操作 DOM 就會很麻煩、甚至可能會干擾框架的行為。

在這種情況下,你必須使用事件,操作對應的數值、然後讓框架或函式庫自行操作、呈現數值的變化。

一開始,我發現有 Window: storage event 似乎能監聽快取變化……但最後發現該事件不能監聽同一頁的快取變化:

Note: This won't work on the same page that is making the changes — it is really a way for other pages on the domain using the storage to sync any changes that are made.

此路不通。那怎麼辦?

探索:Event 操作流

後來發現,開發者其實可以自訂事件,將其綁定在指定 DOM:

const value = "foobar";
const event = new CustomEvent( "shopcarted", { detail: { value } } );

localStorage.setItem( "shopcart", value );
window.dispatchEvent( event );

// In React
class Shopcart extends React.Component {
    constructor(props) {
        super(props);
        this.state = { cart_value: 0 };
    }
    shopcarted() {
        window.addEventListener( "shopcarted", (e) => {
            this.setState({ cart_value: e.detail.value });
        });
    }
    componentDidMount() {
        this.shopcarted();
    }
    render() {
        return ( <div className="shopcart">{this.state.cart_value}</div> );
    }
}

是的。只要設定好事件,然後在接收方寫好指定的行為,這樣就能監聽快取變化了。

參考資料