我正在开发一个用户可以填写调查问卷的应用。每份调查问卷由多个部分组成,每个部分都有一个可选的简介,后面跟着一些问题。每个介绍/问题都在其自己的屏幕上,并带有“下一步”按钮,用户可以点按该按钮以继续下一个问题。
对于这些调查问卷,我有一个StackNavigator
,其中SectionIntroScreen
用于部分介绍,QuestionInputScreen
用于问题。此StackNavigator
嵌套在我的根StackNavigator
内,其中还包含MainTabs
TabNavigator
。
由于并非每个部分都有一个介绍,并且每个部分都有不同数量的输出,因此在开始调查问卷或转到下一个问题时,屏幕推送和跳过的逻辑非常重要。所以,我想把这个逻辑保存在一个生活在问卷堆栈之外的容器中。以下是我尝试这样做:
import React from "react";
import { createStackNavigator, NavigationActions } from "react-navigation";
import { graphql, compose } from "react-apollo";
import { withNavigationProps } from "hoc";
import { LoadingScreen } from "components/UI";
import {
ActivityQuestionInputScreen,
ActivitySectionIntroScreen
} from "../screens";
import { getActivityDetails } from "./queries.gql";
class ActivityInputContainer extends React.Component {
constructor(props) {
super(props);
const { activity } = props;
const initialRoute = activity.sections[0].intro
? "ActivitySectionIntroScreen"
: "ActivityQuestionInputScreen";
const initialQuestionIndex = activity.sections[0].intro ? -1 : 0;
const ActivityInputStack = createStackNavigator(
{
ActivityQuestionInputScreen,
ActivitySectionIntroScreen
},
{
headerMode: "screen",
navigationOptions: {
headerStyle: {
// ...
},
headerTintColor: "#fff"
},
initialRouteName: initialRoute,
initialRouteParams: {
activity,
sectionIndex: 0,
questionIndex: initialQuestionIndex,
onNext: this.handleNext
}
}
);
this.ActivityInputStack = ActivityInputStack;
}
handleNext = ({ sectionIndex, questionIndex }) => {
const { activity } = this.props;
const nextSection =
activity.sections[sectionIndex].questions.length > questionIndex + 1
? sectionIndex
: sectionIndex + 1;
if (nextSection >= activity.sections.length) {
alert("Saving (not really)");
} else {
let nextQuestion = nextSection !== sectionIndex ? -1 : questionIndex + 1;
if (nextQuestion === -1 && !activity.sections[nextSection].intro) {
nextQuestion = 0;
}
const routeName =
nextQuestion === -1 && activity.sections[sectionIndex].intro
? "ActivitySectionIntroScreen"
: "ActivityQuestionInputScreen";
this.stackRef.dispatch(
NavigationActions.navigate({
type: "Navigation/PUSH",
routeName,
params: {
activity,
sectionIndex: nextSection,
questionIndex: nextQuestion,
onNext: this.handleNext
}
})
);
}
};
render() {
const { ActivityInputStack } = this;
return (
<ActivityInputStack
ref={stackRef => {
this.stackRef = stackRef;
}}
/>
);
}
}
const LoadingProxy = ({ data: { loading, error, activity }, ...props }) => {
if (loading || error) {
return <LoadingScreen loading={loading} error={error} />;
}
return <ActivityInputContainer activity={activity} {...props} />;
};
export default compose(
withNavigationProps,
graphql(getActivityDetails, {
options: ({ activityId }) => ({
variables: {
id: activityId
}
})
})
)(LoadingProxy);
这或多或少有效,但有几个问题: