React Native:多屏容器? (带反应导航)

时间:2018-06-14 01:32:16

标签: react-native react-navigation

我正在开发一个用户可以填写调查问卷的应用。每份调查问卷由多个部分组成,每个部分都有一个可选的简介,后面跟着一些问题。每个介绍/问题都在其自己的屏幕上,并带有“下一步”按钮,用户可以点按该按钮以继续下一个问题。

对于这些调查问卷,我有一个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);

这或多或少有效,但有几个问题:

  • 我无法回到之前的问题。而不是回到上一个问题,后退按钮弹出整个堆栈,返回到我开始调查问卷之前的屏幕。调查问卷的标题中没有后退按钮
  • 似乎没有办法将状态从容器传递到各个屏幕。我使用redux解决了这个问题,但我宁愿将状态保存在容器中
  • 我觉得我可能会以错误的方式解决这个问题。这里有什么我想念的吗?一些更好的方法来完成我想要做的事情?

0 个答案:

没有答案