Как загрузить данные из магазина при перенаправлении на новую страницу - PullRequest
1 голос
/ 24 сентября 2019

У меня две страницы;первый называется QuizHomePage и содержит приветственное сообщение и кнопку, позволяющую пользователю начать тест.

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);

actions.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 the QuizContainer component? I tried useEffect which normally behaves as componentDidMount`, но он не работает с моей проблемой.Как я могу это исправить?

Ответы [ 3 ]

1 голос
/ 25 сентября 2019

Вам нужно использовать async и ждать здесь.Если вы не дождетесь разрешения обещания и не перейдете к следующей странице, вы никогда не сможете гарантировать, что пользователь увидит вопрос, как только страница загрузится.

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

Секундаподход: (я не рекомендую) Не выводите вопрос, если у вас нет вопросов, заполненных в избыточном состоянии.

return(
     { questions &&  <ContentQuiz> ... </ContentQuiz> }
)
0 голосов
/ 25 сентября 2019

Я решил свой вопрос с помощью этого обновления:

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;
  loadingData: boolean;
  questions: IQuestion[];
  questionRequest: () => void;
}

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

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

  return (
    <div>
   {loadingData ? ("Loading ...") : (
    <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>
)}
</div>
  );
};

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

  return {
    currentQuestionNumber,
    loadingData,
    questions
  };
};

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

export default connect(mapStateToProps, mapDispatchToProps)(QuizzContainer);
0 голосов
/ 24 сентября 2019

Я рекомендую вам использовать подключенный маршрутизатор для перенаправления вашего пользователя.Это позволяет вам перенаправлять через приставку и между прочим передать ваш объект одновременно.

https://github.com/supasate/connected-react-router

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...