React useWindowVariable

Milk Midi
4 min readAug 19, 2022

--

大家好,我是奶綠
今天來聊聊在 React 裡如何取存 window 變數。

window 很好用,因為他只有一個,所以全站可以共用變數,但 window 裡的變數有更動時,react 不會知道,所以我們要加工一下。
宣告一個 window.update 的函式,改變數的同時,也 dispatch CustomEvent。

window.myVariable = {
name: 'milkmidi',
count: 0,
};
window.update = (name, value) => {
// @ts-ignore
window.myVariable[name] = value;
window.dispatchEvent(new CustomEvent('variableChange'));
};

React 端寫個 useWindowVariable,針聽 window 發出的 CustomEvent。
這裡可以用 React18 useSyncExternalStore,寫法可以更簡潔。

const windowVariableSubscribe = (listener) => {
window.addEventListener('variableChange', listener);
return () => {
window.removeEventListener('variableChange', listener);
};
};
// React18 only
export default function useWindowVariable(name: string) {
return useSyncExternalStore(
windowVariableSubscribe,
() => window.myVariable[name]
);
}

React17 可以這樣寫

export function useWindowVariableReact17(name: string) {
const [value, setValue] = useState(() => window.myVariable[name]);
useEffect(() => {
const listener = () => {
setValue(window.myVariable[name]);
};
window.addEventListener('variableChange', listener);
return () => {
window.removeEventListener('variableChange', listener);
};
}, [name]);
return value;
}

App.tsx 可以這樣用

import useWindowVariable from './hooks/useWindowVariable';export default function App() {
const name = useWindowVariable('name');
const count = useWindowVariable('count');
return (
<div>
<pre>
name:{name}, count:{count}
</pre>
<button
onClick={() => {
window.update('name', Math.random() + '');
window.update('count', count + 1);
}}
>
window.myVariable.name
</button>
</div>
);
}

簡單小巧的 window 共用變數的方法,當然也可以把 myVariable 改用 Proxy 寫,一樣透過發出事件讓 React 知道。
附上原始碼,祝大家學習愉快

--

--