如何用 react-native-navigation v2 中的其他组件替换嵌套堆栈?
How to replace nested stack with other component in react-native-navigation v2?
我正在尝试使用 react-native-navigation v2 构建一个动态向导。
我说动态是因为步骤的数量可能会根据用户选择的选项而有所不同。
我正在考虑使用嵌套堆栈,所以我的应用程序布局看起来像这样:
{
root: {
sideMenu: {
left: {/*...*/},
center: {
stack: {
children: [component1, /*...,*/ componentX]
}
}
}
}
}
ComponentX 是我启动向导的地方,所以我像这样推送一个新堆栈:
{
// ...
stack: {
children: [
component1,
//...,
componentX,
{
stack: {
children: [step1, step2, /*...,*/ stepN]
}
}
]
}
}
用户在 stepN 上做出最后选择后,我想用摘要屏幕替换嵌套堆栈,使其具有如下内容:
{
//...
stack: {
children: [
component1,
//...,
componentX,
summaryScreen
]
}
}
我可以使用 Navigation.setRoot
来重置整个东西,但这意味着我可能必须将导航存储在 Redux 中。
我也尝试过使用 Navigation.setStackRoot
但我的印象是它设置的是父堆栈根而不是我的嵌套堆栈...
我终于解决了。
方法如下:
- 在我的应用程序启动时,当我为我的主堆栈提供一个 id 时
const sideMenu = {
left: { /*...*/ },
center: {
stack: {
id: 'main', // this line is important
children: [/*...*/]
}
},
};
Navigation.setRoot({
root: { sideMenu },
});
- 当我想启动我的向导时,我会推送一个新堆栈
Navigation.push(componentId, {
stack: {
id: 'wizard',
children: [
{
component: { /*...*/ },
},
],
}
})
随着用户的进步,我将屏幕推送到新堆栈 wizard
当我想显示最终摘要屏幕时,我在嵌套堆栈上调用 setStackRoot
Navigation.setStackRoot('wizard', [
{
component: { /*...*/ },
},
]);
- 在该摘要屏幕上,我有一个标记为 'Finish' 的按钮,用于删除嵌套堆栈
Navigation.pop('main');
编辑: 单独使用这种方法,如果您在嵌套屏幕上单击后退箭头,它将关闭整个嵌套堆栈,而不是仅关闭此屏幕。
我不得不按如下方式使用自定义后退按钮:
我使用自定义后退按钮解决了这个问题:
1. 在我想要覆盖按钮的地方推送一个新屏幕时,使用选项
import Icon from 'react-native-vector-icons/MaterialIcons';
/* ... */
const backIcon = await Icon.getImageSource('arrow-back', 24, '#000');
const component = {
id: screenID,
name: screenID,
passProps,
options: {
topBar: {
leftButtons: [
{
id: 'backButton',
icon: backIcon,
},
],
},
}
};
return Navigation.push(componentId, { component });
- 创建一个 HOC 来实现您的自定义返回操作
import React, { Component } from 'react';
import { Navigation } from 'react-native-navigation';
const getDisplayName = WrappedComponent => WrappedComponent.displayName || WrappedComponent.name || 'Component';
export default function withCustomBackButton(WrappedComponent) {
class WithCustomBackButton extends Component {
componentDidMount() {
this.navigationEventListener = Navigation.events().bindComponent(this);
}
componentWillUnmount() {
if (this.navigationEventListener) this.navigationEventListener.remove();
}
navigationButtonPressed() {
// Your custom action
const { componentId } = this.props;
Navigation.pop(componentId);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
WithCustomBackButton.displayName = `WithCustomBackButton(${getDisplayName(WrappedComponent)})`;
return WithCustomBackButton;
}
- 使用自定义后退按钮注册屏幕时,将其包装在您的 HOC 中
import withCustomBackButton from '../components/hoc/WithCustomBackButton';
/* ... */
Navigation.registerComponent('selectLocation', () => withCustomBackButton(SelectLocation));
我正在尝试使用 react-native-navigation v2 构建一个动态向导。
我说动态是因为步骤的数量可能会根据用户选择的选项而有所不同。
我正在考虑使用嵌套堆栈,所以我的应用程序布局看起来像这样:
{
root: {
sideMenu: {
left: {/*...*/},
center: {
stack: {
children: [component1, /*...,*/ componentX]
}
}
}
}
}
ComponentX 是我启动向导的地方,所以我像这样推送一个新堆栈:
{
// ...
stack: {
children: [
component1,
//...,
componentX,
{
stack: {
children: [step1, step2, /*...,*/ stepN]
}
}
]
}
}
用户在 stepN 上做出最后选择后,我想用摘要屏幕替换嵌套堆栈,使其具有如下内容:
{
//...
stack: {
children: [
component1,
//...,
componentX,
summaryScreen
]
}
}
我可以使用 Navigation.setRoot
来重置整个东西,但这意味着我可能必须将导航存储在 Redux 中。
我也尝试过使用 Navigation.setStackRoot
但我的印象是它设置的是父堆栈根而不是我的嵌套堆栈...
我终于解决了。
方法如下:
- 在我的应用程序启动时,当我为我的主堆栈提供一个 id 时
const sideMenu = {
left: { /*...*/ },
center: {
stack: {
id: 'main', // this line is important
children: [/*...*/]
}
},
};
Navigation.setRoot({
root: { sideMenu },
});
- 当我想启动我的向导时,我会推送一个新堆栈
Navigation.push(componentId, {
stack: {
id: 'wizard',
children: [
{
component: { /*...*/ },
},
],
}
})
随着用户的进步,我将屏幕推送到新堆栈
wizard
当我想显示最终摘要屏幕时,我在嵌套堆栈上调用 setStackRoot
Navigation.setStackRoot('wizard', [
{
component: { /*...*/ },
},
]);
- 在该摘要屏幕上,我有一个标记为 'Finish' 的按钮,用于删除嵌套堆栈
Navigation.pop('main');
编辑: 单独使用这种方法,如果您在嵌套屏幕上单击后退箭头,它将关闭整个嵌套堆栈,而不是仅关闭此屏幕。
我不得不按如下方式使用自定义后退按钮:
我使用自定义后退按钮解决了这个问题: 1. 在我想要覆盖按钮的地方推送一个新屏幕时,使用选项
import Icon from 'react-native-vector-icons/MaterialIcons';
/* ... */
const backIcon = await Icon.getImageSource('arrow-back', 24, '#000');
const component = {
id: screenID,
name: screenID,
passProps,
options: {
topBar: {
leftButtons: [
{
id: 'backButton',
icon: backIcon,
},
],
},
}
};
return Navigation.push(componentId, { component });
- 创建一个 HOC 来实现您的自定义返回操作
import React, { Component } from 'react';
import { Navigation } from 'react-native-navigation';
const getDisplayName = WrappedComponent => WrappedComponent.displayName || WrappedComponent.name || 'Component';
export default function withCustomBackButton(WrappedComponent) {
class WithCustomBackButton extends Component {
componentDidMount() {
this.navigationEventListener = Navigation.events().bindComponent(this);
}
componentWillUnmount() {
if (this.navigationEventListener) this.navigationEventListener.remove();
}
navigationButtonPressed() {
// Your custom action
const { componentId } = this.props;
Navigation.pop(componentId);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
WithCustomBackButton.displayName = `WithCustomBackButton(${getDisplayName(WrappedComponent)})`;
return WithCustomBackButton;
}
- 使用自定义后退按钮注册屏幕时,将其包装在您的 HOC 中
import withCustomBackButton from '../components/hoc/WithCustomBackButton';
/* ... */
Navigation.registerComponent('selectLocation', () => withCustomBackButton(SelectLocation));