首页 > 解决方案 > 重定向到新页面时如何从redux store加载数据

问题描述

我有两页;第一个调用QuizHomePage并包含欢迎消息和允许用户开始测验的按钮。

测验主页.tsx:

import Button from "@material-ui/core/Button";
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import React from "react";
import { connect } from "react-redux";
import { Dispatch } from "redux";
import { questionRequest, startQuiz } from "../../actions/index";
import AppBar from "../../components/common/AppBar";
import history from "../../history/history";

const useStyles = makeStyles((theme: Theme) =>
    createStyles({
        root: {
            textAlign: "center",
            margin: theme.spacing(10)
        },
        button: {
            marginTop: theme.spacing(6)
        }

    }));

interface IProps {
    questionRequest: () => void;
    startQuiz: () => void;
}

const QuizHomePage = (props: IProps) => {
    const classes = useStyles();

    const { questionRequest, startQuiz } = props;

    const handleStartQuiz = () => {
        questionRequest();
        startQuiz();
        return history.push("/contentQuiz");
    };
    return (<>
        <AppBar />
        <div className={classes.root}>
            <Typography
                color="textPrimary"
                gutterBottom
                variant="h2">
                Test your javascript skills
            </Typography>
            <Typography
                color="textSecondary"
                gutterBottom
                variant="h6">
                Please click the start button to launch the Quiz
        </Typography>
            <Button
                className={classes.button}
                color="secondary"
                onClick={handleStartQuiz}
                variant="contained">Start</Button>
        </div>
    </>);
};

const mapDispatchToProps = (dispatch: Dispatch) => {
    return {
        startQuiz: () => dispatch(startQuiz()),
        questionRequest: () => dispatch<any>(questionRequest())
    };
};

export default connect(null, mapDispatchToProps)(QuizHomePage);

当我单击Start按钮时,我分派了 2 个动作questionRequest,它们执行一个承诺并从数据库中返回所有问题的列表,并startQuiz调度一个动作来更新测验的状态,然后用户将被重定向到由描述的测验问题页面这段代码:

import { Typography } from "@material-ui/core";
import React from "react";
import { connect } from "react-redux";
import SyntaxHighlighter from "react-syntax-highlighter";
import { dark } from "react-syntax-highlighter/dist/esm/styles/prism";
import { incrementQuestion, IQuestion } from "../../actions/index";
import ContentQuiz from "../../components/ContentQuiz";

interface IProps {
  currentQuestionNumber: number;
  questions: IQuestion[];
}

const QuizzContainer = (props: IProps) => {
  const { currentQuestionNumber, questions } = props;

  const currentQuestion = questions[currentQuestionNumber];
  const handleNextQuiz = () => {
    incrementQuestion();
  };

  return (
    <ContentQuiz
      questionNumber={currentQuestionNumber}
      handleClick={handleNextQuiz}>
      <div>
        <Typography variant="h3" gutterBottom> What's the output of </Typography>
        <>
          <SyntaxHighlighter language="javascript" style={dark}>
            {currentQuestion.questionDescription}
          </SyntaxHighlighter>
        </>

      </div>
    </ContentQuiz>
  );
};

const mapStateToProps = (state: any) => {
  const { currentQuestionNumber, questions } = state.quiz;

  return {
    currentQuestionNumber,
    questions
  };
};

export default connect(mapStateToProps, { incrementQuestion })(QuizzContainer);

动作.ts:

export const questionRequest = (): ThunkAction<void, AppState, null, Action<string>> => {
  return async (dispatch: Dispatch) => {
    dispatch(startQuestionRequest());
    getQuestionsApi().then((response: AxiosResponse) => {
      const { data } = response;
      dispatch(questionSuccess(data.result));
    },
      (error: AxiosError) => {
        let errorMessage = "Internal Server Error";
        if (error.response) {
          errorMessage = error.response.data.error;
        }
        dispatch(questionFail(errorMessage));
        dispatch(errorAlert(errorMessage));
      });
  };
};

我收到一个错误:

TypeError: Cannot read property 'questionDescription' of undefined

这通常是因为对于反应,questions变量是未定义的。我意识到问题数组并没有快速更新,但是由于服务器响应,这就是为什么 QuizzContainer returns the error mentioned below when it tries to mount the component. Is it a good approach to lazy load the component in order to wait the fetching of questions from server and then mounting theQuizContainer component? I trieduseEffect which normally behaves ascomponentDidMount 一段时间后,但它不适用于我的问题。我该如何解决?

标签: reactjstypescriptreduxreact-reduxreact-router

解决方案


您需要在这里使用 async 和 await 。如果您不等到承诺得到解决并将用户导航到下一页,则您永远无法保证用户在页面加载后会立即看到问题。

 const handleStartQuiz = async () => {
        awit questionRequest();
        await startQuiz();
        return history.push("/contentQuiz");
    }

第二种方法:(我不推荐) 除非您在 redux 状态下填写了问题,否则不要呈现问题。

return(
     { questions &&  <ContentQuiz> ... </ContentQuiz> }
)

推荐阅读