Rails Back end React Front End Trivia App with External API
Published: 2023-03-30 15:51:17

#Final Project

Finally a chance to put together all the skills that were learned over a 15 week bootcamp.  This project uses an external API to get questions then stores those questions on a rails backend along with users and user scores to track high scores.

All of the following code implements a trivia game within a single React Component. This component utilizes React hooks, such as useState and useEffect, as well as React Router and a custom UserContext. The component fetches a list of 10 trivia questions from an external API, saves them to a database, and renders each question one at a time. The user provides an answer to each question, and their score is incremented if they answer correctly. When all questions have been answered, the user's final score is displayed, and they are given the option to return to the homepage.

#React Hooks

The code utilizes several React hooks to manage the component's state. useState is used to store the current state of several variables, such as showResults, currentQuestion, score, questions, and answer. The useState hook returns an array with two elements: the current state value and a function to update that value.

```
const {user, setUser} = useContext(UserContext)
    const [showResults, setShowResults] = useState(false);
    const [currentQuestion, setCurrentQuestion] = useState(0);
    const [score, setScore] = useState(0);
    const [questions, setQuestions] = useState([])
    const [answer, setAnswer] = useState("")
    const navigate = useNavigate()
```

useEffect is used to fetch the trivia questions from an external API and save them to a database using a POST request. The useEffect hook runs only once, when the component first mounts, since it has an empty dependency array. This means that the API call and database update only occur once, not on every render.

```
useEffect(() => {
        const fetchData = async () => {
            try {
              const resp = await fetch("https://the-trivia-api.com/api/questions?limit=10&categories=science,history'")
              const questionsList = await resp.json()
              
              const questionResponse = await fetch('/questions', {
                method: 'POST',
                headers: {
                  'Content-Type': 'application/json',
                },
                body: JSON.stringify({ questions: questionsList }),
              })
              const questionData = await questionResponse.json()
              
              setQuestions(questionData)
              
            } catch (error) {
              alert(error)
            }
          }
        fetchData()
        //for each question create question.question
        //create question
        //create answer for each create question.answer
        //create question answer for each question for the current user attach the question and answer that was asked to the user
        
      },[])
```

#React Router

The code imports two functions from React Router: useNavigate and Link. useNavigate is used to programmatically navigate to a different page, while Link is used to create clickable links that lead to a different page. In this code, if currentUserGame is null, useNavigate is used to redirect the user to the homepage. If the user reaches the end of the game and clicks the "Return Home" button, Link is used to take them back to the homepage.

#Custom UserContext

The code imports UserContext from a custom context, which is used to share data between components without passing props down through every level of the component tree. The UserContext provides two values: user and setUser, both obtained through useContext. The user object contains information about the current user, including their user_games. setUser is a function that allows the user object to be updated.

#Trivia Game Logic

The trivia game begins by rendering the first question from the questions array. The user provides an answer to the question in an input field, and when they click "Final Answer," the answerSubmitted function is called. This function compares the user's answer to the correct answer stored in the current question object. If the user's answer is correct, their score is incremented, and the score is saved to the database using a PATCH request. The user's current game object is also updated with their new score, and the setCurrentUserGame function is called to update the component's state with the new game object.

```
const answerSubmitted = (e) => {
        e.preventDefault()
        // Increment the score
        if (answer.toLowerCase() === questions[currentQuestion].answer.answer_text.toLowerCase()) {
          setAnswer("")
          // debugger
          fetch(`/user_games/${user.user_games[user.user_games.length -1].id}`, {
            method: 'PATCH',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify( {score: score + 1} )
          })
          .then(response => {
            console.log(response)
            
            if (response.status === 200) {
              response.json().then(data => {
                // console.log(data)
                setScore(currentScore => currentScore + 1);
                setUser(currentUserObj => ({...currentUserObj, user_games: currentUserObj.user_games.map(ug => ug.id === data.id ? data : ug)}))
                setCurrentUserGame(data)
              })
            } else {
              response.json().then(error => alert(error.errors))
            }
          })
          .catch(error => alert(error));
        }
    
        if (currentQuestion < 9) {
          setCurrentQuestion(thisQuestion => thisQuestion + 1);
          setAnswer("");
        } else {
          setShowResults(true);
        }
      };
```

If the user's answer is incorrect or they reach the end of the game, the function updates the component's state to show the results screen. If the user reaches the end of the game, they are shown their final score and given the option to return to the homepage.

```
  if(!currentUserGame){navigate('/welcome')}
      if (questions.length === 0) return <h1>Loading...</h1>
      console.log(questions, currentQuestion)
```

#Conclusion

In summary, this code is a React component that implements a trivia game. The component uses several React hooks to manage its state, React Router to navigate to different pages, and a custom UserContext to share data between components. The game logic fetches trivia questions from an external API, saves them to a database, and renders each question one at a time. The user provides an answer to each question, and their score is incremented if they answer correctly. When all questions have been answered, the user's final score is displayed, and they are given the option to return to the homepage.