Toma Tomov
Toma Tomov

Reputation: 1704

render method is fired two times

This is my code:

   import React from "react";
import { View, StyleSheet, StatusBar, Text, SafeAreaView } from "react-native";

import { Button, ButtonContainer } from "../components/Button";
import { Alert } from "../components/Alert";
import firebase from "../config/firebase";
import "firebase/firestore";

const styles = StyleSheet.create({
  container: {
    backgroundColor: "red",
    flex: 1,
    paddingHorizontal: 20
  },
  text: {
    color: "#fff",
    fontSize: 25,
    textAlign: "center",
    letterSpacing: -0.02,
    fontWeight: "600"
  },
  safearea: {
    flex: 1,
    marginTop: 100,
    justifyContent: "space-between"
  }
});

class Quiz extends React.Component {
  state = {
    correctCount: 0,
    totalCount: 0,
    activeQuestionIndex: 0,
    answered: false,
    answerCorrect: false,
    questions: []
  };

  async componentDidMount() {
    await this.questions();
  }

  questions = async () => {
    const documents = await firebase
      .firestore()
      .collection("questions")
      .where("quizId", "==", this.props.navigation.getParam("uid"))
      .get();
    const questions = documents.docs.map(doc => {
      return { uid: doc.id, ...doc.data() };
    });

    return this.setState({ questions });
  };

  answer = correct => {
    this.setState(
      state => {
        const nextState = { answered: true };

        if (correct) {
          nextState.correctCount = state.correctCount + 1;
          nextState.answerCorrect = true;
        } else {
          nextState.answerCorrect = false;
        }

        return nextState;
      },
      () => {
        setTimeout(() => this.nextQuestion(), 750);
      }
    );
  };

  nextQuestion = () => {
    this.setState(state => {
      const nextIndex = state.activeQuestionIndex + 1;

      if (nextIndex >= state.totalCount) {
        return this.props.navigation.navigate("Result", {
          correct: this.state.correctCount
        });
      }

      return {
        activeQuestionIndex: nextIndex,
        answered: false
      };
    });
  };

  render() {
    console.log(this.state.questions);
    const questions = this.props.navigation.getParam("questions", []);
    const question = questions[this.state.activeQuestionIndex];

    return (
      <View
        style={[
          styles.container,
          { backgroundColor: this.props.navigation.getParam("color") }
        ]}
      >
        <StatusBar barStyle="light-content" />
        <SafeAreaView style={styles.safearea}>
          <View>
            <Text style={styles.text}>
              {this.state.activeQuestionIndex + 1}.{question.question}
            </Text>

            <ButtonContainer>
              {question.answers.map(answer => (
                <Button
                  key={answer.id}
                  text={answer.text}
                  onPress={() => this.answer(answer.correct)}
                />
              ))}
            </ButtonContainer>
          </View>

          {/* <Text style={styles.text}>
            {`${this.state.correctCount}/${this.state.totalCount}`}
          </Text> */}
        </SafeAreaView>
        {/* <Alert
          correct={this.state.answerCorrect}
          visible={this.state.answered}
        /> */}
      </View>
    );
  }
}

export default Quiz;

console.log is fired two time. First time it return empty array and the second time it return the expected elements. As I understand, because of the async on my componentDidMount the second time is rendered because of the questions method, where the state is changed in it. Did I understand it right ? And my question is how can I prevent that ? Because this way error is thrown on the first render because the code below breaks. Thank you!

Upvotes: 0

Views: 35

Answers (1)

AKX
AKX

Reputation: 169388

Your questions are being loaded asynchronously after mount.

I'd suggest changing your initial questions to be undefined, e.g.

  state = {
    ...
    questions: undefined
  };

and checking for that in your render. If questions is undefined, things are still being loaded.

render() {
  if(this.state.questions === undefined) return null;
  // ...

Upvotes: 1

Related Questions