webrix
webrix copied to clipboard
Use an internal ref to eliminate the need for `useMemo()`
Currently, when using Movable.useMove()
or Resizable.useResize()
, you need to wrap the list of provided operations in a useMemo
. We can eliminate the need for useMemo
if we maintain the list of operation in a ref
internally, and access the operations through the ref
only.
Following these instruction, we get the following solution:
export const useMove = ops => {
const opsRef = useRef(ops);
const shared = useRef({});
const onBeginMove = useCallback(e => {
opsRef.current.forEach(({onBeginMove}) => onBeginMove(e, shared.current));
}, [opsRef]);
...
};
However, if we look at this use case from Scrollable\components\HorizontalScrollbar\HorizontalScrollbar.jsx:
const props = Movable.useMove(useMemo(() => [move(container, thumb, track)], [container]));
The ops prop can change.
This is an issue because the value inside the hook won't change once we use useRef, meaning we will always use the initial value of ops.
You need to keep the ref
updated:
opsRef.current = ops;
We do this in various hooks, see this for example: https://github.com/open-amdocs/webrix/blob/master/src/hooks/useAnimationFrame/useAnimationFrame.js#L24
Ok, I understand everything now, thanks for that example!
export const useMove = ops => {
const shared = useRef({});
const opsRef = useRef();
opsRef.current = ops;
const onBeginMove = useCallback(e => {
opsRef.current.forEach(({onBeginMove}) => onBeginMove(e, shared.current));
}, []);
const onMove = useCallback(e => {
opsRef.current.forEach(({onMove}) => onMove(e, shared.current));
}, []);
const onEndMove = useCallback(e => {
opsRef.current.forEach(({onEndMove}) => onEndMove(e, shared.current))
}, []);
return {onBeginMove, onMove, onEndMove};
};
Closed as part of PR https://github.com/open-amdocs/webrix/pull/85