javascript - Förhindra att useEffect-hooken med två beroenden körs två gånger
Jag vill använda två egenskaper av ett tillstånd i samma useEffect-hook:
state.keyEvent: keydown från document (för att lyssna på kommandon som Ctrl + R).
state.value: värdet av input (för att utföra en textsökning).
import { useEffect, useReducer } from "react";
const App = () => {
const initialState = { keyEvent: {}, value: "builder" };
const [state, updateState] = useReducer(
(state: any, updates: any) => ({ ...state, ...updates }),
initialState
);
function handleInputChange(event: any) {
updateState({ value: event.target.value });
}
function handleDocumentKeyDown(event: any) {
updateState({ keyEvent: event });
}
useEffect(() => {
document.addEventListener("keydown", handleDocumentKeyDown);
return () => {
document.removeEventListener("keydown", handleDocumentKeyDown);
};
}, []);
useEffect(() => {
console.log("keyEvent:", state);
}, [state]);
return (
<div>
<input
id="input"
type="text"
onChange={handleInputChange}
value={state.value}
/>
</div>
);
};
export default App;
Detta fungerar—utom att useEffect-hooken körs två gånger när jag skriver i input-elementet.
Jag tror att jag måste säga till koden: Om state.value uppdateras, ignorera state.keyEvent och kör inte hooken igen.
Är det korrekt? Om så är fallet, hur uppnår man detta?
Obs: om jag placerar state.keyEvent och state.useEffect i olika useEffect-hooks, kommer jag inte att kunna ha det senaste värdet av state.value i hooken som innehåller state.keyEvent (eftersom hooken som innehåller state.keyEvent kommer att köras före hooken som innehåller state.value).
Svar #1
Om du bara vill lyssna efter kommandon som ctrl+r kan du förfiltrera dem i din tangentbordshanterare och utesluta dem från att skickas till inmatningen:
....
function isCommand(event: KeyboardEvent) {
return event.ctrlKey && event.key === 'r';
}
function handleDocumentKeyDown(event: KeyboardEvent) {
if (isCommand(event)) {
event.preventDefault();
updateState({ keyEvent: event });
}
}
Svar #2
keydown-händelsen utlöses alltid först, så det räcker att kolla efter den
useEffect(() => {
console.log("keyEvent:", state);
}, [state.keyEvent]);