使用 Context API 动态设置抽屉位置时,React 导航抽屉打开不一致
React navigation drawer doesn't open consistently when dynamically setting drawer position using the Context API
我正在尝试实现一个抽屉位置和内容可以动态更改的抽屉。
我有一个抽屉导航器,里面有一个堆栈导航器。堆栈导航器的 header 有两个按钮。左侧按钮将 drawerPosition
设置为 "left"
并调用 navigations.openDrawer()
,右侧按钮将 drawerPosition
设置为 "right"
并调用 navigation.openDrawer()
。
我当前的实现如下所示:
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>
);
}
所以我使用react context来共享和更新当前抽屉位置
我遇到的现象是,打开左边的抽屉总是会正确打开抽屉,但打开右边的抽屉大多数时候不会正确打开抽屉。我只看到背景阴影而不是抽屉。
我的第一个猜测是在打开抽屉之前上下文没有更新,但是将组件转换为 class-based 组件并使用 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 === 'right' ? DIRECTION_RIGHT : DIRECTION_LEFT,
);
}
从你链接的零食中弄乱,似乎上下文实际上已经更新了。仅当您从“右”切换到“左”时才会出现此问题。 (这个我在inspector看到的有点支持,但是没深挖)
查看此 updated snack 记录位置 updates/bubbles 并默认为“正确”位置。如果你先点击右按钮,你可以看到它工作,但如果你点击左按钮,它就会崩溃。
总而言之,恕我直言,这是一个 reactnavigation 错误。这个问题似乎只出现在 drawerType="front"
中,因此作为解决方法,您可以尝试向 Drawer.Navigator
.
添加 drawerType="back"
属性
我正在尝试实现一个抽屉位置和内容可以动态更改的抽屉。
我有一个抽屉导航器,里面有一个堆栈导航器。堆栈导航器的 header 有两个按钮。左侧按钮将 drawerPosition
设置为 "left"
并调用 navigations.openDrawer()
,右侧按钮将 drawerPosition
设置为 "right"
并调用 navigation.openDrawer()
。
我当前的实现如下所示:
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>
);
}
所以我使用react context来共享和更新当前抽屉位置
我遇到的现象是,打开左边的抽屉总是会正确打开抽屉,但打开右边的抽屉大多数时候不会正确打开抽屉。我只看到背景阴影而不是抽屉。
我的第一个猜测是在打开抽屉之前上下文没有更新,但是将组件转换为 class-based 组件并使用 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 === 'right' ? DIRECTION_RIGHT : DIRECTION_LEFT,
);
}
从你链接的零食中弄乱,似乎上下文实际上已经更新了。仅当您从“右”切换到“左”时才会出现此问题。 (这个我在inspector看到的有点支持,但是没深挖)
查看此 updated snack 记录位置 updates/bubbles 并默认为“正确”位置。如果你先点击右按钮,你可以看到它工作,但如果你点击左按钮,它就会崩溃。
总而言之,恕我直言,这是一个 reactnavigation 错误。这个问题似乎只出现在 drawerType="front"
中,因此作为解决方法,您可以尝试向 Drawer.Navigator
.
drawerType="back"
属性