我正在使用react 导航V6和上下文API,当我从我的组件导航到屏幕时,上下文状态image即使包装了我的组件,也变成了undefined.下面是我的组件和屏幕中的代码流和相关代码.

EXPECTED OUTPUT -> image context state should persist (as I'm using context provider)
ACTUAL OUTPUT -> image context state becomes undefined when I navigate to different screen.

AppStack

const AppStack = () => {
  return (
    <Stack.Navigator>
      <Stack.Screen name={'AppDrawer'} component={AppDrawer} />
      <Stack.Screen name={'StoreStack'} component={StoreStack} />
    </Stack.Navigator>

  )
}

AppDrawer

const AppDrawer = () => {
  return (
    <Drawer.Navigator>
      <Drawer.Screen name={'AppBotTab'} component={AppBotTab} />
    </Drawer.Navigator>
  )
}

AppBotTab

const BotTab = createBottomTabNavigator();
const AppBotTab = () => {
  return (
    <BotTab.Navigator>
      <BotTab.Screen name='CameraPreview' component={CameraPreview} />
      //... other screens
    </BotTab.Navigator>
  )
}

CameraPreview-gt;罪魁祸首(看起来像)

const CameraPreview = ({ navigation }) => {
  const isFocused = useIsFocused();
  const cameraRef = React.useRef<ExpoCamera>(null);
  const [isCameraReady, setIsCameraReady] = useState(false);
  const [cameraType, setCameraType] = useState(CameraType.back);

  return (
        isFocused && (
            <Camera
                cameraRef={cameraRef}
                cameraType={cameraType}
                flashMode={flashMode}
                onCameraReady={() => setIsCameraReady(true)}>
                  <MediaContextProvider>
                    <CameraControls
                      isCameraReady={isCameraReady}
                      onToggleCamera={toggleCamera}
                      setFlashMode={setFlashMode}
                      cameraRef={cameraRef}
                      onDismiss={() => navigation?.goBack()}
                    />
                  </MediaContextProvider>
            </Camera>
        )
    );
}

CameraControls

const CameraControls = () => {
  const { image, setImageAndUpdateSize } = useMedia();
  const [cameraState, setCameraState] = useState('PREVIEW');
  
  useEffect(() => {
        console.log('Mounting CAMERA CONTROLS');
        return () => {
            console.log('image: ', image); // undefined
            console.log('Umnounting CAMERA CONTROLS'); // gets called when navigating to StoreStack screen
        };
  }, []);

  const takePhoto = async () => {
        if (cameraRef.current) {
            const data = await cameraRef.current.takePictureAsync(CAMERA_OPTIONS);
            const source = data.uri;
            if (source) {
                setImageAndUpdateSize({ path: source })
                cameraRef.current.pausePreview();
                setCameraState('IMAGE_PREVIEW');
            }
        }
  };

  switch (cameraState) {
        case 'PREVIEW':
            return <CameraPreviewControls onTakePhoto={takePhoto} />;
        case 'IMAGE_PREVIEW':
            if (!image?.path) return null;
            return <PhotoPreview imageURI={image?.path} />;
        default:
            return null;
    }
}

PhotoPreview


const PhotoPreview = ({ imageURI }) => {
  useEffect(() => {
        console.log('Mounting PHOTO REVIEW');
        return () => {
            console.log('Umnounting PHOTO PREVIEW'); // gets called when navigating to StoreStack screen
        };
  }, []);

  return (
    <ImageBackground source={{uri:imageURI}} />
    //... other components
    <FiltersPanel />
  )
}

FiltersPanel

const FiltersPanel = () => {
  ...
  return (
    //...
    <Gifts />
  )
}

Gifts Component

const Gifts = () => {
  const navigation = useNavigation();
  const goToStore = () => {
      navigation.navigate('StoreStack', {
          screen: StoreStackPages.StoreScreen,
      });
  };

    return (
        <TouchableOpacity onPress={goToStore}>
            <Image source={GIFT} resizeMode="contain" style={styles.image} />
        </TouchableOpacity>
    );
}

MediaContext

const MediaContext = createContext({
  // other default values
  setImage: () => {},
});

const MediaContextProvider = ({ children }) => {
  const [image, setImage] = useState<Partial<PickerImage>>();
  // other states
  return (
    <MediaContextProvider value={{image, setImage}}></MediaContextProvider>
  )
}

export const useMedia = () => {
  const context = useContext(MediaContext);
  const setImageAndUpdateSize = (capturedImage) => {
    const {setImage} = context;
    return setImage(capturedImage);
  }

  return {
    ...context,
    // other functions & utilities
    setImageAndUpdateSize
  }
}

这就是整个流程.所以,简单地说,问题是when I capture a photo in 100, the 101 is set successfully and as the 102 now changes to 'IMAGE_PREVIEW', the 103 component gets mounted, and I can see the 104 loaded with my context 101, now when I tap the 106 icon (being in the 103 component), I navigate to 108, BUT NOW when I go back from StoreStack, the context 101 changes to 110 and the 102 changes to 112,这不应该是这种情况,因为我仍然被包装在MediaContextProvider下,所以image上下文状态不应该是undefined,而且当我导航到StoreStack并出现时,CameraControlsPhotoPreview组件被卸载,这在React导航中也不应该是这样的,根据Reaction导航文档,当我们导航到一个屏幕时,前一个屏幕不会被卸载.

如果有人能解释一下这一点,那将是非常有用的!!

提前谢谢您!

推荐答案

UseIsFocused在您离开时触发重现.当您回来时,上下文将重新呈现.可以移除useIsFocused以在导航离开时停止重现器.

Reactjs相关问答推荐

条件索引路由

CreateBrowserRouter将props 传递给父组件以验证权限

替换谷歌 map api默认信息窗口与自定义

如何在NextJS中仅在刷新页面和页面淡出页面过渡时添加全屏加载器

禁止直接访问Next.js中的页面,同时允许从应用程序内部访问

react 挂钩-使用有效澄清

透明MOV文件未出现在我的React网页中

生产部署:控制台中 Firebase 无效 api 密钥错误

设置自定义形状的纹理

如何在 React Native 中渲染下面的对象数组?

如何管理组件列表的复杂状态? (Nextjs/ReactJS)

获取 不能显示为 的后代.错误,但不太确定如何构建我的代码以避免此警告

Reactjs:MUI5:MobileDateTimePicker API:如何自定义日历中的文本

从ReactDataGridtry 将数据传递给父组件

使用 map 循环浏览列表列表中的列表并显示它们

添加 React/Redux 组件模板的 VS Code 扩展

如何使用react 路由将 url 参数限制为一组特定的值?

Lodash 在命名导入中导入整个包

Context Api React 的问题

如何在 React 中制作动画?