簡而言之:
我想在值更改時發生副作用,但前提是第二個值是true. 由于兩個值都必須在依賴陣列中,所以當第一個值不變而第二個值打開時也會觸發副作用,但我不希望它這樣做。
詳細:
我正在 React 中創建一個游戲。我想在各種活動中播放(短)音效,例如輸贏。我有一個簡單的輔助函式來播放聲音,它有效:
function playSound(url) {
new Audio(url).play();
}
所有的游戲邏輯都在一個自定義的 hook 中useGame。當用戶移動時,這個鉤子回傳一個點擊處理程式(它處理更新鉤子中的所有相關狀態)和一個winner布林值(指示游戲是否獲勝)。
我無法呼叫playSound點擊處理程式,因為該關閉只能訪問點擊前狀態,并且不知道點擊后游戲是否獲勝。所以我把它放在一個副作用中,用一個依賴陣列來確保它只在贏得比賽時發生一次。
useEffect(() => {
if (winner) {
playSound(winSound);
}, [winner]);
[注:在內部,winner是無狀態的;它是直接從(有狀態的)董事會計算出來的。所以沒有setWinner我可以標記的電話。]
到這里為止,這一切都很好。但現在我想添加一個用戶設定來靜音所有聲音。
const [soundIsOn, setSoundIsOn] = useState(true);
現在我必須將其添加為呼叫的條件playSound(或將其作為引數傳遞給它)。
useEffect(() => {
if (winner && soundIsOn) {
playSound(winSound);
}, [winner, soundIsOn]);
請注意,依賴項陣列現在需要包含soundIsOn. 問題出現在聲音關閉,用戶贏得游戲,然后用戶稍后打開聲音時。此效果將在soundIsOn更改后被呼叫,從而產生獲勝聲音。
我已經閱讀了所有檔案并尋找了類似的問題。我見過的唯一可能的解決方案是在自定義鉤子中使用 ref來跟蹤以前的狀態并檢查哪個狀態發生了變化,但這似乎有點混亂和不令人滿意。有沒有一種“正確”的方法來處理這種型別的事情?理想情況下,要么通過修改效果,要么以某種方式將其處理到點擊處理程式中。
uj5u.com熱心網友回復:
解決方案#1
管理具有其他狀態而不是獲勝者物件本身的觸發事件。
const [winner, _setWinner] = useState(...);
const [shouldPlaySound, setShouldPlaySound] = useState(false);
// wrapper function (it is not required)
const setWinner = (winner) => {
setShouldPlaySound(true);
_setWinner(winner)
}
...
// if winner is selected
setWinner(...);
...
// Side effect
useEffect(() => {
if(shouldPlaySound && soundIsOn){
playSound(winSound);
}
setShouldPlaySound(false);
}, [shouldPlaySound, soundIsOn])
而且,新setWinner包裝的功能并不需要與定義useCallback,因為它僅包括setStateS的useState。
但是setWinner不需要定義包裝器。這是您對代碼可讀性的選擇。
解決方案#2
但是我認為如果您需要在選擇獲勝者時播放聲音,請playSound在選擇獲勝者時呼叫。
// when winner is selected
setWinner(winner);
if(soundIsOn){
playSound(winSound);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/338059.html
