[英]Calling a method (that mutates state) from two different useEffect
我在玩React Hooks,從兩個不同的useEffect調用一個方法(改變狀態)。 給出以下代碼:
function App() {
const [clicked, setClicked] = useState(false);
/**
* Listen for clicked changes. When clicked changes to true,
* allow setCounterAndSetUrlHash to do it's thing, before accpeting
* the next click. So the clicked flag is simply a valve, that opens
* after two seconds.
*/
useEffect(() => {
if (clicked) {
setCounterAndSetUrlHash(counter + 1);
setTimeout(() => {
setClicked(false);
}, 2000);
}
}, [clicked]);
const [counter, setCounter] = useState(0);
/**
* Listen for changes in the URL hash. When the user presses
* the back button in the browser toolbar, decrement the
* counter value.
*/
useEffect(() => {
window.onhashchange = () => {
const value = Number(window.location.hash.replace("#", ""));
// must be number
if (typeof value === "number" && value % 1 === 0) {
if (counter - 1 === value) {
setCounterAndSetUrlHash(counter - 1);
}
}
};
});
/**
* Set a new counter value and apply the same value
* to the URL hash. I want to reuse this function
* in both useEffect above.
*/
const setCounterAndSetUrlHash = value => {
setCounter(value);
if (value === 0) {
window.location.hash = "";
} else {
window.location.hash = String(value);
}
};
return (
<div className="App">
<p>Clicked: {String(clicked)}</p>
<p>Counter: {counter}</p>
<button type="button" onClick={() => setClicked(true)}>
Click me
</button>
</div>
);
}
運行中的代碼: https : //codesandbox.io/s/dreamy-shadow-7xesm
該代碼實際上正在工作。 但是我收到此警告。
React Hook useEffect缺少依賴項:“計數器”。 包括它或刪除依賴項數組。 (反應鈎/詳盡的下降)
..而且我不確定在保持當前功能的情況下該如何遵循。 當我添加計數器依賴項時,我會遇到無限循環。
您的第一個效果使用counter
狀態變量,但其依賴項列表不包括它。 將其包含在依賴項列表中將創建無限循環。
您可以通過使用setCounter
函數類型參數來消除對counter
的依賴。
function App() {
const [clicked, setClicked] = useState(false);
/**
* Listen for clicked changes. When clicked changes to true,
* allow setCounterAndSetUrlHash to do it's thing, before accpeting
* the next click. So the clicked flag is simply a valve, that opens
* after two seconds.
*/
useEffect(() => {
if (clicked) {
incrCounter(1);
setTimeout(() => {
setClicked(false);
}, 2000);
}
}, [clicked]);
const [counter, setCounter] = useState(0);
/**
* Listen for changes in the URL hash. When the user presses
* the back button in the browser toolbar, decrement the
* counter value.
*/
useEffect(() => {
window.onhashchange = () => {
const value = Number(window.location.hash.replace("#", ""));
// must be number
if (typeof value === "number" && value % 1 === 0) {
if (counter - 1 === value) {
incrCounter(- 1);
}
}
};
});
useEffect(() => {
if (counter === 0) {
window.location.hash = "";
} else {
window.location.hash = String(counter);
}
}, [counter])
/**
* Set a new counter value and apply the same value
* to the URL hash. I want to reuse this function
* in both useEffect above.
*/
const incrCounter = delta => {
setCounter(value => value + delta);
};
return (
<div className="App">
<p>Clicked: {String(clicked)}</p>
<p>Counter: {counter}</p>
<button type="button" onClick={() => setClicked(true)}>
Click me
</button>
</div>
);
}
嘗試使用功能性setState, setState((state, props) => stateChange)
useEffect(() => {
if (clicked) {
setCounterAndSetUrlHash(counter => counter + 1);
setTimeout(() => {
setClicked(false);
}, 2000);
}
}, [clicked]);
為了使用第一個計數器值解決onhashchange
回調的問題,我建議將功能移到setCounter
的回調中。 這也意味着按鈕和哈希更改需要其他功能。
還要在頂部以及useEffect
之后設置變量和useState
定義,以便可以使用它們。 如果您希望useEffect
只運行一次,請設置一個空數組依賴項; 忽略依賴項將在每個渲染器上運行。
export const App = () => {
const [clicked, setClicked] = useState(false);
const [counter, setCounter] = useState(0);
/**
* Listen for clicked changes. When clicked changes to true,
* allow setCounterAndSetUrlHash to do it's thing, before accpeting
* the next click. So the clicked flag is simply a valve, that opens
* after two seconds.
*/
useEffect(() => {
if (clicked) {
setCounter(counter => {
const value = counter + 1;
if (value === 0) {
window.location.hash = "";
} else {
window.location.hash = String(value);
}
return value;
});
setTimeout(() => {
setClicked(false);
}, 2000);
}
}, [clicked]);
/**
* Listen for changes in the URL hash. When the user presses
* the back button in the browser toolbar, decrement the
* counter value.
*/
useEffect(() => {
window.onhashchange = e => {
const value = Number(window.location.hash.replace("#", ""));
// must be number
if (typeof value === "number" && value % 1 === 0) {
setCounter(counter => {
if (counter - 1 !== value) {
return counter;
}
if (value === 0) {
window.location.hash = "";
} else {
window.location.hash = String(value);
}
return value;
});
}
};
}, []);
return (
<div className="App">
<p>Clicked: {String(clicked)}</p>
<p>Counter: {counter}</p>
<button type="button" onClick={() => setClicked(true)}>
Click me
</button>
</div>
);
};
向第一個useEffect()添加計數器:
const [counter, setCounter] = useState(0);
useEffect(() => {
if (clicked) {
setCounterAndSetUrlHash(counter + 1);
setTimeout(() => {
setClicked(false);
}, 2000);
}
}, [clicked, counter]);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.