使用 Context API 动态设置抽屉位置时,React 导航抽屉无法始终打开 [英] React navigation drawer doesn't open consistently when dynamically setting drawer position using the Context API

查看:42
本文介绍了使用 Context API 动态设置抽屉位置时,React 导航抽屉无法始终打开的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一个抽屉位置和内容可以动态更改的单个抽屉.

我有一个抽屉导航器,里面有一个堆栈导航器.堆栈导航器的标题有两个按钮.左侧按钮将 drawerPosition 设置为 left" 并调用 navigations.openDrawer(),右侧按钮设置 drawerPositionright" 并调用 navigation.openDrawer().

我目前的实现是这样的:

const Stack = createStackNavigator();const Drawer = createDrawerNavigator();const DrawerPositionContext = React.createContext([{}, () => {}]);const DrawerPositionProvider = (props) =>{const [drawerPosition, setDrawerPosition] = useState({});返回 (<DrawerPositionContext.Provider value={[drawerPosition, setDrawerPosition]}>{props.children}</DrawerPositionContext.Provider>);};功能自定义抽屉内容(道具){返回 (<DrawerContentScrollView {...props}>{props.drawerPosition === '左' ?(<DrawerItem label="左"/>) : (<DrawerItem label="Right";/>)}</DrawerContentScrollView>);}const Screen1 = () =>{return Screen1;};const useDrawerPosition = () =>{const [drawerPosition, setDrawerPosition] = React.useContext(抽屉位置上下文);返回 {抽屉位置,设置抽屉位置};};const DrawerNavigator = () =>{const { drawerPosition, setDrawerPosition } = useDrawerPosition();返回 (<Drawer.Navigator抽屉位置={抽屉位置}drawerContent={(props) =>(<CustomDrawerContent {...props} drawerPosition={drawerPosition}/>)}><Drawer.Screen name="stack navigator";组件={StackNavigator}/></Drawer.Navigator>);};const StackNavigator = ({导航}) =>{const { setDrawerPosition } = useDrawerPosition();返回 (<堆栈导航器屏幕选项={{headerLeft: () =>(<按钮标题=左"onPress={() =>{setDrawerPosition(左");导航.openDrawer();}}/>),headerRight: () =>(<按钮标题=正确"onPress={() =>{setDrawerPosition(右");导航.openDrawer();}}/>)}}><Stack.Screen name="screen1";组件={屏幕1}/></Stack.Navigator>);};导出默认函数 App() {返回 (<DrawerPositionProvider><导航容器><抽屉导航器/></NavigationContainer></DrawerPositionProvider>);}

所以我使用 react 上下文来共享和更新当前的抽屉位置.

我遇到的情况是,打开左侧抽屉始终可以正确打开抽屉,但大多数情况下打开右侧抽屉无法正确打开抽屉.我只看到背景阴影,而不是抽屉.

小吃


我的第一个猜测是在抽屉打开之前上下文没有更新,但是将组件转换为基于类的组件并使用 setState 回调给出了相同的结果,所以我不确定这里发生了什么.

我知道执行此类操作的通常实现是创建以某种方式嵌套的两个抽屉,但是可以使用我尝试过的方法来实现吗?


更新

我认为这是一个错误.问题似乎出在 Drawer.tsx (https://github.com/react-navigation/react-navigation/blob/main/packages/drawer/src/views/Drawer.tsx).>

我对 Animated 不太熟悉(https://reactnative.dev/docs/animated),但我认为问题出在 componentDidUpdate 中的这段代码:

if (prevProps.drawerPosition !== drawerPosition) {this.drawerPosition.setValue(drawerPosition === '正确' ?DIRECTION_RIGHT : DIRECTION_LEFT,);}

解决方案

从弄乱您链接的小吃来看,似乎上下文实际上已更新.只有当您从正确"切换时才会出现问题.到左".(这点在inspector里面看到的有点支持,不过我没深挖).

请参阅此更新的零食,它在更新/冒泡时记录位置并默认为对"位置.如果你先点击右键,你可以看到它在工作,但如果你点击左键,它就会坏掉.

总而言之,恕我直言,这是一个反应导航错误.这是一个似乎只出现在 drawerType="front" 中的问题,因此作为一种解决方法,您可以尝试将 drawerType="back" 属性添加到 >Drawer.Navigator.

I'm trying to implement a single drawer whose drawer position and content can be dynamically changed.

I have a drawer navigator with a stack navigator inside. The header of the stack navigator has two buttons. The left button sets the drawerPosition to "left" and calls navigations.openDrawer() and the right button sets the drawerPosition to "right" and calls navigation.openDrawer().

My current implementation looks like this:

const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();

const DrawerPositionContext = React.createContext([{}, () => {}]);

const DrawerPositionProvider = (props) => {
  const [drawerPosition, setDrawerPosition] = useState({});
  return (
    <DrawerPositionContext.Provider value={[drawerPosition, setDrawerPosition]}>
      {props.children}
    </DrawerPositionContext.Provider>
  );
};

function CustomDrawerContent(props) {
  return (
    <DrawerContentScrollView {...props}>
      {props.drawerPosition === 'left' ? (
        <DrawerItem label="Left" />
      ) : (
        <DrawerItem label="Right" />
      )}
    </DrawerContentScrollView>
  );
}

const Screen1 = () => {
  return <Text>Screen1</Text>;
};

const useDrawerPosition = () => {
  const [drawerPosition, setDrawerPosition] = React.useContext(
    DrawerPositionContext
  );

  return {
    drawerPosition,
    setDrawerPosition
  };
};

const DrawerNavigator = () => {
  const { drawerPosition, setDrawerPosition } = useDrawerPosition();

  return (
    <Drawer.Navigator
      drawerPosition={drawerPosition}
      drawerContent={(props) => (
        <CustomDrawerContent {...props} drawerPosition={drawerPosition} />
      )}
    >
      <Drawer.Screen name="stack navigator" component={StackNavigator} />
    </Drawer.Navigator>
  );
};

const StackNavigator = ({ navigation }) => {
  const { setDrawerPosition } = useDrawerPosition();

  return (
    <Stack.Navigator
      screenOptions={{
        headerLeft: () => (
          <Button
            title="left"
            onPress={() => {
              setDrawerPosition("left");
              navigation.openDrawer();
            }}
          />
        ),
        headerRight: () => (
          <Button
            title="right"
            onPress={() => {
              setDrawerPosition("right");
              navigation.openDrawer();
            }}
          />
        )
      }}
    >
      <Stack.Screen name="screen1" component={Screen1} />
    </Stack.Navigator>
  );
};

export default function App() {
  return (
    <DrawerPositionProvider>
      <NavigationContainer>
        <DrawerNavigator />
      </NavigationContainer>
    </DrawerPositionProvider>
  );
}

So I use react context to share and update the current drawer position.

The behavior I'm experiencing is that opening the left drawer will always open the drawer correctly, but opening the right drawer will not open the drawer correctly most of the time. Instead of the drawer I only see the backdrop shadow.

snack


My first guess was that the context isn't updated before the drawer is opened, but converting the components to class-based components and using a setState callback gave the same result, so I'm not sure what is happening here.

I know the usual implementation for doing something like this is to create two drawers nested in a certain way, but it is it possible to do it with the approach I've tried?


Update

I think this is a bug. The problem seems to be inside Drawer.tsx (https://github.com/react-navigation/react-navigation/blob/main/packages/drawer/src/views/Drawer.tsx).

I'm not that familiar with Animated (https://reactnative.dev/docs/animated), but I think the problem is this code in componentDidUpdate:

if (prevProps.drawerPosition !== drawerPosition) {
  this.drawerPosition.setValue(
    drawerPosition === 'right' ? DIRECTION_RIGHT : DIRECTION_LEFT,
  );
}

解决方案

From messing around with the snack you linked, it seems like the context is actually updated. The problem only appears if you switch from "right" to "left". (This is somewhat supported by what I saw in the inspector, but I didn't dig deep).

See this updated snack that logs the position as it updates/bubbles and defaults to the "right" position. If you click the right button first, you can see it working, but if you click left it will break.

All in all, this is a reactnavigation bug IMHO. This is a problem that only seems to appear with drawerType="front", so as a workaround you could try adding a drawerType="back" prop to Drawer.Navigator.

这篇关于使用 Context API 动态设置抽屉位置时,React 导航抽屉无法始终打开的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆