在很多集思广益、撰写法典和打字之后(在大查小组的帮助下),我最后提出了一些似乎解决我问题的法典。 它可能不是精心设计的、简单、高效的、符合最佳做法的,但似乎在我使用的情况下是正确的。
I would be glad to get feedback on this solution, and if you know of a more efficient, React-friendly way of handling this problem, I would love to know about it!
Below is a revised version of my code that aims to provide a solution to the simplified problem (using a, b, and c) that I originally posted.
const useCustomHookArgs = [ foo , bar ]
// useCustomHook needs to be adapted to take a flag based on which it may or may not reset its state.
// I reset its state when using it in conjunction with useEventDependentEffect, but otherwise
// pass shouldResetState = false in the rest of my code
const useCustomHook = (shouldResetState = false, ...useCustomHookArgs) => {
const [b, setB] = useState(null);
const [shouldReset, setShouldReset] = useState(false);
// Use an effect to set b and an internal shouldReset flag based on the shouldResetState arg
useEffect(() => {
const fetchData = async () => {
// Logic to fetch data based on args
const fetchedData = /* fetch logic */;
setB(fetchedData);
if (shouldResetState) {
setShouldReset(true); // Flag needed to reset b after it has been used
}
};
unsubscribeFromStore = subscribeToStore();
fetchData();
return () => {
unsubscribeFromStore();
};
}, [...useCustomHookArgs]);
// Use an effect to reset b (and the shouldReset flag) after it has been used
useEffect(() => {
if (shouldReset) {
setB(null);
setShouldReset(false);
}
}, [shouldReset]);
return b;
};
// useEventDependentEffect is a custom hook that captures the logic needed to
// capture a at the time of the eventHandler call, and then compute b from a
const useEventDependentEffect = (eventHandler, effectFunction, aToCapture, computeB, computeBArgs) => {
const [trigger, setTrigger] = useState(0);
const capturedARef = useRef();
const [capturedA, setCapturedA] = useState(null);
const [computedB, setComputedB] = useState(null);
const shouldResetState = true;
const newComputedB = computeB(shouldResetState, ...computeBArgs, capturedA);
useEffect(() => {
if (newComputedB != null && newComputedB !== computedB) {
setComputedB(newComputedB);
}
}, [newComputedB, computedB]);
// Enhanced event handler to capture a and trigger the effect
const enhancedEventHandler = useCallback((...args) => {
eventHandler(...args);
capturedARef.current = aToCapture.current;
setTrigger(trigger + 1); // Trigger the effect
}, [eventHandler, trigger]);
// Effect that runs the desired logic with the captured a
useEffect(() => {
if (trigger) {
const newCapturedA = capturedARef.current;
// Compare newCapturedA with the current capturedA
if (newCapturedA !== capturedA) {
setCapturedA(newCapturedA);
}
if(computedB != null) {
// Call effectFunction with the computed b to run the logic
// that needed to run below setA(c) in the original problem
effectFunction(computedB, capturedARef.current);
setTrigger(0); // Reset the trigger
setComputedB(null);
setCapturedA(null);
}
}
}, [trigger, effectFunction, capturedA, computeB, computedB]);
return enhancedEventHandler;
};
function MyComponent(props) {
const [a, setA] = useState(null);
const aRef = useRef(a);
const eventHandler = (event) => {
const c = event.data;
setA(c);
aRef.current = c;
};
const effectFunction = async (b, a) => {
try {
if (b) {
// logic using a
} else {
// more logic using a
}
} catch (e) {
console.error(`Error:`, e);
}
};
const aToCapture = {
a: aRef
}
const handleEvent = useEventDependentEffect(eventHandler, effectFunction, aToCapture, useCustomHook, useCustomHookArgs);
// Render logic and event binding using handleEvent
}