有時我必須使用一些原生的 js libaray api,所以我可能有一個這樣的組件:
function App() {
const [state, setState] = useState(0)
useEffect(() => {
const container = document.querySelector('#container')
const h1 = document.createElement('h1')
h1.innerHTML = 'h1h1h1h1h1h1'
container.append(h1)
h1.onclick = () => {
console.log(state)
}
}, [])
return (
<div>
<button onClick={() => setState(state => state 1)}>{state}</button>
<div id="container"></div>
</div>
)
}
上面是一個簡單的例子。我應該在安裝反應后初始化庫,并系結一些事件處理程式。問題來了:如上圖所示,如果我使用useEffect()withoutstate作為依賴項陣列中的項,則stateonclick 處理程式中的值可能永遠不會改變。但是如果我添加state到依賴項陣列中,每次狀態更改時都會執行效果函式。上面是一個簡單的例子,但是真正的庫的初始化可能非常昂貴,所以這種方式是不可能的。
現在我找到了 3 種方法來解決這個問題,但沒有一個能讓我滿意。
- 創建一個 ref 以保持狀態,并添加一個效果以在
current每次更改時更改它state。(一個額外的變數和效果) - 與第一個類似,但在函式之外定義一個變數而不是
ref. (有些是第一個) - 使用類組件。(這個太多了)
那么是否有一些解決方案可以解決問題并使代碼變得更好?
uj5u.com熱心網友回復:
我認為您已經很好地總結了這些選項。我只想添加一個選項,即您可以將代碼拆分為一個初始化效果和一個僅更改 onclick 的效果。初始化邏輯可以只運行一次,onclick 可以運行每個渲染:
const [state, setState] = useState(0)
const h1Ref = useRef();
useEffect(() => {
const container = document.querySelector('#container')
const h1 = document.createElement('h1')
h1Ref.current = h1;
// Do expensive initialization logic here
}, [])
useEffect(() => {
// If you don't want to use a ref, you could also have the second effect query the dom to find the h1
h1ref.current.onClick = () => {
console.log(state);
}
}, [state]);
此外,您可以稍微簡化選項#1。您不需要創建 useEffect 來更改ref.current,您可以在組件的主體中執行此操作:
const [state, setState] = useState(0);
const ref = useRef();
ref.current = state;
useEffect(() => {
const container = document.querySelector('#container');
// ...
h1.onClick = () => {
console.log(ref.current);
}
}, []);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/451968.html
