react-native#InteractionManager TypeScript Examples
The following examples show how to use
react-native#InteractionManager.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: CachedImage.tsx From lexicon with MIT License | 6 votes |
async componentDidMount() {
this._interaction = InteractionManager.runAfterInteractions(async () => {
if (this.props.source.uri) {
const filesystemURI = await this.getImageFilesystemKey(
this.props.source.uri,
);
await this.loadImage(filesystemURI, this.props.source.uri);
}
});
}
Example #2
Source File: use-after-interactions.ts From react-navigation-heavy-screen with MIT License | 6 votes |
useAfterInteractions = () => {
const [areInteractionsComplete, setInteractionsComplete] = useState(false)
const subscriptionRef = useRef<ReturnType<
typeof InteractionManager.runAfterInteractions
> | null>(null)
const transitionRef = useRef<TransitioningView>(null)
useEffect(() => {
subscriptionRef.current = InteractionManager.runAfterInteractions(
() => {
transitionRef.current?.animateNextTransition()
setInteractionsComplete(true)
subscriptionRef.current = null
}
)
return () => {
subscriptionRef.current?.cancel()
}
}, [])
return {
areInteractionsComplete,
transitionRef,
}
}
Example #3
Source File: DevPersistedNavigationContainer.tsx From mobile with Apache License 2.0 | 5 votes |
function DevPersistedNavigationContainerImpl(
{persistKey, onStateChange, ...others}: DevPersistedNavigationContainerProps,
forwardedRef: React.Ref<NavigationContainerRef>,
) {
const [isReady, setIsReady] = React.useState(false);
const [initialState, setInitialState] = React.useState<InitialState | undefined>();
const persistInteractionRef = React.useRef<{cancel: () => void} | null>(null);
const onStateChangeInternal = React.useCallback(
state => {
const persistState = async () => {
persistInteractionRef.current = null;
try {
await AsyncStorage.setItem(persistKey, JSON.stringify(state));
} catch (ex) {
console.warn(`Failed to persist state. ${ex.message}`);
}
};
if (persistInteractionRef.current !== null) {
persistInteractionRef.current.cancel();
}
if (state != null) {
persistInteractionRef.current = InteractionManager.runAfterInteractions(persistState);
}
if (onStateChange != null) {
onStateChange(state);
}
},
[onStateChange, persistKey],
);
React.useEffect(() => {
const loadPersistedState = async () => {
try {
const jsonString = await AsyncStorage.getItem(persistKey);
if (jsonString != null) {
setInitialState(JSON.parse(jsonString));
}
setIsReady(true);
} catch (ex) {
console.warn(`Failed to load state. ${ex.message}`);
setIsReady(true);
}
};
loadPersistedState();
}, [persistKey]);
if (!isReady) {
return null;
}
return (
<NavigationContainer
{...others}
key={persistKey}
ref={forwardedRef}
initialState={initialState}
onStateChange={onStateChangeInternal}
/>
);
}
Example #4
Source File: DevPersistedNavigationContainer.tsx From mobile with Apache License 2.0 | 5 votes |
function DevPersistedNavigationContainerImpl(
{persistKey, onStateChange, ...others}: DevPersistedNavigationContainerProps,
forwardedRef: React.Ref<NavigationContainerRef>,
) {
const [isReady, setIsReady] = React.useState(false);
const [initialState, setInitialState] = React.useState<InitialState | undefined>();
const persistInteractionRef = React.useRef<{cancel: () => void} | null>(null);
const onStateChangeInternal = React.useCallback(
state => {
const persistState = async () => {
persistInteractionRef.current = null;
try {
await AsyncStorage.setItem(persistKey, JSON.stringify(state));
} catch (error) {
captureException(`Failed to persist state.`, error);
}
};
if (persistInteractionRef.current !== null) {
persistInteractionRef.current.cancel();
}
if (state != null) {
persistInteractionRef.current = InteractionManager.runAfterInteractions(persistState);
}
if (onStateChange != null) {
onStateChange(state);
}
},
[onStateChange, persistKey],
);
React.useEffect(() => {
const loadPersistedState = async () => {
try {
const jsonString = await AsyncStorage.getItem(persistKey);
if (jsonString != null) {
setInitialState(JSON.parse(jsonString));
}
setIsReady(true);
} catch (error) {
captureException(`Failed to load state.`, error);
setIsReady(true);
}
};
loadPersistedState();
}, [persistKey]);
if (!isReady) {
return null;
}
return (
<NavigationContainer
{...others}
key={persistKey}
ref={forwardedRef}
initialState={initialState}
onStateChange={onStateChangeInternal}
/>
);
}
Example #5
Source File: Card.tsx From nlw2-proffy with MIT License | 5 votes |
private handleStartInteraction = () => {
if (this.interactionHandle === undefined) {
this.interactionHandle = InteractionManager.createInteractionHandle();
}
};
Example #6
Source File: Card.tsx From nlw2-proffy with MIT License | 5 votes |
private handleEndInteraction = () => {
if (this.interactionHandle !== undefined) {
InteractionManager.clearInteractionHandle(this.interactionHandle);
this.interactionHandle = undefined;
}
};
Example #7
Source File: Pager.tsx From react-native-gallery-toolkit with MIT License | 4 votes |
Pager = typedMemo(function Pager<
TPages,
ItemT = UnpackItemT<TPages>,
>({
pages,
initialIndex,
totalCount,
numToRender = 2,
onIndexChange = workletNoop,
renderPage,
width = dimensions.width,
gutterWidth = GUTTER_WIDTH,
shouldRenderGutter = true,
keyExtractor,
pagerWrapperStyles = {},
getItem,
springConfig,
onPagerTranslateChange = workletNoop,
onGesture = workletNoop,
onEnabledGesture = workletNoop,
shouldHandleGestureEvent = workletNoopTrue,
initialDiffValue = 0,
shouldUseInteractionManager = true,
outerGestureHandlerRefs = [],
verticallyEnabled = true,
}: PagerProps<TPages, ItemT>) {
assertWorklet(onIndexChange);
assertWorklet(onPagerTranslateChange);
assertWorklet(onGesture);
assertWorklet(onEnabledGesture);
assertWorklet(shouldHandleGestureEvent);
// make sure to not calculate translate with gutter
// if we don't want to render it
if (!shouldRenderGutter) {
gutterWidth = 0;
}
const getPageTranslate = useWorkletCallback(
(i: number) => {
const t = i * width;
const g = gutterWidth * i;
return -(t + g);
},
[gutterWidth, width],
);
const pagerRef = useRef(null);
const tapRef = useRef(null);
const isActive = useSharedValue(true);
const onPageStateChange = useWorkletCallback((value: boolean) => {
isActive.value = value;
}, []);
const velocity = useSharedValue(0);
const isMounted = useRef(false);
const [diffValue, setDiffValue] = useState(initialDiffValue);
useEffect(() => {
if (shouldUseInteractionManager && !isMounted.current) {
InteractionManager.runAfterInteractions(() => {
setDiffValue(numToRender);
console.log('numToRender in interaction');
});
isMounted.current = true;
} else {
setDiffValue(numToRender);
}
}, [numToRender]);
// S2: Pager related stuff
const [activeIndex, setActiveIndex] = useState(initialIndex);
const index = useSharedValue(initialIndex);
const length = useSharedValue(totalCount);
const pagerX = useSharedValue(0);
const toValueAnimation = useSharedValue(
getPageTranslate(initialIndex),
);
const offsetX = useSharedValue(getPageTranslate(initialIndex));
const totalWidth = useDerivedValue(() => {
return length.value * width + gutterWidth * length.value - 2;
}, []);
const onIndexChangeCb = useWorkletCallback((nextIndex: number) => {
onIndexChange(nextIndex);
runOnJS(setActiveIndex)(nextIndex);
}, []);
const onIndexChangeWorklet = useWorkletCallback((i: number) => {
offsetX.value = getPageTranslate(i);
index.value = i;
onIndexChangeCb(i);
}, []);
useEffect(() => {
runOnUI(onIndexChangeWorklet)(initialIndex);
}, [initialIndex]);
const getSpringConfig = useWorkletCallback(
(noVelocity?: boolean) => {
const ratio = 1.1;
const mass = 0.4;
const stiffness = IS_ANDROID ? 200.0 : 100.0;
const damping = ratio * 2.0 * Math.sqrt(mass * stiffness);
const configToUse =
typeof springConfig !== 'undefined'
? springConfig
: {
stiffness,
mass,
damping,
restDisplacementThreshold: 1,
restSpeedThreshold: 5,
};
// @ts-ignore
// cannot use merge and spread here :(
configToUse.velocity = noVelocity ? 0 : velocity.value;
return configToUse;
},
[springConfig],
);
const onChangePageAnimation = useWorkletCallback(
(noVelocity?: boolean) => {
const config = getSpringConfig(noVelocity);
if (offsetX.value === toValueAnimation.value) {
return;
}
offsetX.value = withSpring(
toValueAnimation.value,
config,
(isCanceled) => {
if (!isCanceled) {
velocity.value = 0;
}
},
);
},
[getSpringConfig],
);
// S3 Pager
const getCanSwipe = useWorkletCallback(
(currentTranslate: number = 0) => {
const nextTranslate = offsetX.value + currentTranslate;
if (nextTranslate > 0) {
return false;
}
const totalTranslate =
width * (length.value - 1) + gutterWidth * (length.value - 1);
if (Math.abs(nextTranslate) >= totalTranslate) {
return false;
}
return true;
},
[width, gutterWidth],
);
const getNextIndex = useWorkletCallback(
(v: number) => {
const currentTranslate = Math.abs(
getPageTranslate(index.value),
);
const currentIndex = index.value;
const currentOffset = Math.abs(offsetX.value);
const nextIndex = v < 0 ? currentIndex + 1 : currentIndex - 1;
if (
nextIndex < currentIndex &&
currentOffset > currentTranslate
) {
return currentIndex;
}
if (
nextIndex > currentIndex &&
currentOffset < currentTranslate
) {
return currentIndex;
}
if (nextIndex > length.value - 1 || nextIndex < 0) {
return currentIndex;
}
return nextIndex;
},
[getPageTranslate],
);
const isPagerInProgress = useDerivedValue(() => {
return (
Math.floor(Math.abs(getPageTranslate(index.value))) !==
Math.floor(Math.abs(offsetX.value + pagerX.value))
);
}, [getPageTranslate]);
const onPan = useAnimatedGestureHandler<
PanGestureHandlerGestureEvent,
{
pagerActive: boolean;
offsetX: null | number;
}
>({
onGesture: (evt) => {
onGesture(evt, isActive);
if (isActive.value && !isPagerInProgress.value) {
onEnabledGesture(evt);
}
},
onInit: (_, ctx) => {
ctx.offsetX = null;
},
shouldHandleEvent: (evt) => {
return (
(evt.numberOfPointers === 1 &&
isActive.value &&
Math.abs(evt.velocityX) > Math.abs(evt.velocityY) &&
shouldHandleGestureEvent(evt)) ||
isPagerInProgress.value
);
},
onEvent: (evt) => {
velocity.value = clampVelocity(
evt.velocityX,
MIN_VELOCITY,
MAX_VELOCITY,
);
},
onStart: (_, ctx) => {
ctx.offsetX = null;
},
onActive: (evt, ctx) => {
// workaround alert
// the event triggers with a delay and first frame value jumps
// we capture that value and subtract from the actual one
// so the translate happens on a second frame
if (ctx.offsetX === null) {
ctx.offsetX =
evt.translationX < 0 ? evt.translationX : -evt.translationX;
}
const val = evt.translationX - ctx.offsetX;
const canSwipe = getCanSwipe(val);
pagerX.value = canSwipe ? val : friction(val);
},
onEnd: (evt, ctx) => {
const val = evt.translationX - ctx.offsetX!;
const canSwipe = getCanSwipe(val);
offsetX.value += pagerX.value;
pagerX.value = 0;
const nextIndex = getNextIndex(evt.velocityX);
const vx = Math.abs(evt.velocityX);
const translation = Math.abs(val);
const isHalf = width / 2 < translation;
const shouldMoveToNextPage = (vx > 10 || isHalf) && canSwipe;
// we invert the value since the translationY is left to right
toValueAnimation.value = -(shouldMoveToNextPage
? -getPageTranslate(nextIndex)
: -getPageTranslate(index.value));
onChangePageAnimation(!shouldMoveToNextPage);
if (shouldMoveToNextPage) {
index.value = nextIndex;
onIndexChangeCb(nextIndex);
}
},
});
const onTap = useAnimatedGestureHandler({
shouldHandleEvent: (evt) => {
return evt.numberOfPointers === 1 && isActive.value;
},
onStart: () => {
cancelAnimation(offsetX);
},
onEnd: () => {
onChangePageAnimation(true);
},
});
const pagerStyles = useAnimatedStyle<ViewStyle>(() => {
const translateX = pagerX.value + offsetX.value;
onPagerTranslateChange(translateX);
return {
width: totalWidth.value,
transform: [
{
translateX,
},
],
};
}, []);
const pagerRefs = useMemo<PageRefs>(() => [pagerRef, tapRef], []);
const pagesToRender = useMemo(() => {
const temp = [];
for (let i = 0; i < totalCount; i += 1) {
let itemToUse;
if (typeof getItem === 'function') {
itemToUse = getItem(pages, i);
} else if (Array.isArray(pages)) {
itemToUse = pages[i];
} else {
throw new Error(
'Pager: items either should be an array of getItem should be defined',
);
}
const shouldRender = getShouldRender(i, activeIndex, diffValue);
if (!shouldRender) {
temp.push(null);
} else {
temp.push(
<Page
key={keyExtractor(itemToUse, i)}
item={itemToUse}
currentIndex={index}
pagerRefs={pagerRefs}
onPageStateChange={onPageStateChange}
index={i}
length={totalCount}
gutterWidth={gutterWidth}
renderPage={renderPage}
getPageTranslate={getPageTranslate}
width={width}
isPagerInProgress={isPagerInProgress}
shouldRenderGutter={shouldRenderGutter}
/>,
);
}
}
return temp;
}, [
activeIndex,
diffValue,
keyExtractor,
getItem,
totalCount,
pages,
getShouldRender,
index,
pagerRefs,
onPageStateChange,
gutterWidth,
renderPage,
getPageTranslate,
width,
isPagerInProgress,
shouldRenderGutter,
]);
return (
<View style={StyleSheet.absoluteFillObject}>
<Animated.View style={[StyleSheet.absoluteFill]}>
<PanGestureHandler
ref={pagerRef}
minDist={0.1}
minVelocityX={0.1}
activeOffsetX={[-4, 4]}
activeOffsetY={verticallyEnabled ? [-4, 4] : undefined}
simultaneousHandlers={[tapRef, ...outerGestureHandlerRefs]}
onGestureEvent={onPan}
>
<Animated.View style={StyleSheet.absoluteFill}>
<TapGestureHandler
ref={tapRef}
maxDeltaX={10}
maxDeltaY={10}
simultaneousHandlers={pagerRef}
onGestureEvent={onTap}
>
<Animated.View
style={[StyleSheet.absoluteFill, pagerWrapperStyles]}
>
<Animated.View style={StyleSheet.absoluteFill}>
<Animated.View style={[styles.pager, pagerStyles]}>
{pagesToRender}
</Animated.View>
</Animated.View>
</Animated.View>
</TapGestureHandler>
</Animated.View>
</PanGestureHandler>
</Animated.View>
</View>
);
})