diff --git a/apps/src/tests/issue-tests/Test4811.tsx b/apps/src/tests/issue-tests/Test4811.tsx new file mode 100644 index 0000000000..e1e96ff1cf --- /dev/null +++ b/apps/src/tests/issue-tests/Test4811.tsx @@ -0,0 +1,95 @@ +import React, { useEffect, useState } from 'react'; +import { Button, StyleSheet, Text, View } from 'react-native'; +import { + ScreenStack, + ScreenStackHeaderCenterView, + ScreenStackHeaderLeftView, + ScreenStackHeaderRightView, + ScreenStackItem, +} from 'react-native-screens'; + +// https://github.com/software-mansion/react-native-screens/issues/4811 (iOS) +// +// Press "Start". Without the fix the app crashes within a few seconds with +// "Collection <__NSArrayM> was mutated while being enumerated". +// +// `updateHeaderStateInShadowTreeInContextOfNavigationBar:` loops over `reactSubviews`. +// A header item that was just mounted sends its frame to the shadow tree synchronously, +// and that can mount the next pending commit. Here the left and right items toggle at +// different rates, so that commit adds or removes a header subview during the loop. +// Fast enumeration only notices it when it moves on to the next element, so the title +// is placed after the right item. + +function HeaderItem() { + return ; +} + +export default function App() { + const [running, setRunning] = useState(false); + const [tick, setTick] = useState(0); + + useEffect(() => { + if (!running) { + return; + } + let timer: ReturnType; + const loop = () => { + setTick(t => t + 1); + timer = setTimeout(loop, 0); + }; + loop(); + return () => clearTimeout(timer); + }, [running]); + + return ( + + + {tick % 2 === 0 && ( + + + + )} + {tick % 3 !== 0 && ( + + + + )} + + + + + ), + }}> + +