ReactJS-The Beginner Master Class
  • React In the Beginning
    • Lesson 1 - Demo: Build a Simple React App - Fast
    • Lesson 2 - HTML Review
    • Lesson 3 - CSS Review
    • Lesson 4 - Modern JavaScript (JSX) Patterns
    • Lesson 5 - Set up Dev Environment
    • Hands-on Practice
  • React Fundamentals
    • Lesson 1 - Understanding Old vs New Way of Building Web Apps - SPAs
    • Lesson 2 - Motivation for Using React as the Solution to Vanilla JS
    • Lesson 3 - What is ReactJS - How it Works
    • React Code Along from Scratch
    • Lesson 4 - Create and Run a React Project with Vite - Full Overview
    • Lesson 5 - Create Hook by State Management in React
    • Lesson 6 - React Project File and Folder Walkthrough
    • Lesson 7 - JSX and How React Treats the DOM & JSX Compilation(by Babeljs) - Overview
    • Lesson 8 - Understanding the Main Files - App.jsx and main.jsx
    • Lesson 9 - Props and One-Way Data Flow - Overview
    • Lesson 10 - Google Bookshelf App - Ver 1.0
    • Hands-on Practice I
    • Hands-on Practice II
  • React State and Styling
    • Lesson 1 - Pulling Book Data from a Different Data File
    • Lesson 2 - Overview of How State Works in React
    • Lesson 3 - RandomQuote App
    • Lesson 4 - Lifting State Up - React Pattern Overview
    • Hands-On - Simple Counter
  • Forms and Interactivity - Grocery List App
    • Lesson 1 - Setup a Simple Form and Input
    • Lesson 2 - Build Form Profile App Using Multi-input Form Data
    • Hands-on : Build a Grocery List App
  • Connecting to the Backend - Consuming APIs - UseEffect Hook
    • Lesson 1 - Connecting to the Back End - Understanding Side Effects, Hooks and useEffect - Overview
    • Lesson 2 - Fetching Data from the Backend the Right Way with useEffect Hook
    • Lesson 3 - Setting Up Loading State
    • Hands-on :Use Dependency Array and Adding Values that Control Side Effects
  • Solo Project 1
  • RESTful APIs :Build a BookSearch App -Ver 2.0
    • Lesson 1: Build and test RESTful APIs with Postman
    • Lesson 2 - BookShelf App Structure
    • Lesson 3 - Create NavBar.jsx Component
    • Lesson 4 - Create Footer Component
    • Lesson 5 - Create BookList.jsx Component
    • Lesson 6 - Create BookCard.jsx Component
    • Lesson 7 - Creating Custom Hooks - useBooks and api-client
    • Lesson 8 - Controlling Network Activities in React with AbortController
    • Lesson 9 - Show Book Details in a Modal - Working
    • Lesson 10 - Bookshelf App Summary
  • Multi-Page Applications (MPAs)
    • Build a Multi-Page React Application
    • Multi-Page React Application
    • Hands-on Practice
  • Backend Frameworks-NEXT.JS
    • Migrating from React to Next.js
    • Lesson 1: Key Concepts of NodeJS and Express for Backend Web Development
    • Lesson 2: How to set up a new Next.js project
    • Lesson 3: How to create Layouts and Pages
    • Hands-on Practice 1
    • Hands on Practice 2
      • New Project & Folder Structure
      • File-Based Routing
      • Server vs Client Components & Router Hooks
      • Start On The Navbar
      • Navbar Links, Dropdowns & React Icons
      • Active Links & Conditional Rendering
      • Homepage Components
      • Properties Page
      • Property Card Dynamic Data
      • Home Property Listings
      • Custom Not Found & Loading Pages
  • Git and GitHubs
    • Git Installation
    • Git Commands
    • GitHub Repository
    • Hands-on Practice
  • Database in Application
    • React Supabase CRUD
    • Hands-on: Note Taking App
  • NoSQL Database
    • Installing MongoDB Community Edition
    • System Env Path Setting
    • How to use MongoDB Shell
    • How to Connect and Use Mongosh in VS Code via MongoDB Extension
    • MongoDB Guide
  • Solo Project 2
  • Deployment and Web Hosting
    • Lesson 1. React+Vite+TS+Shadcn Project
    • Lesson 2. Deploying a React Vite App to Vercel from Vercel CLI
    • Lesson 3 Connecting to GitHub Repo and Automate Deployment
  • Solo Project 3
  • Final Term Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 2 Team Project
    • Level 2 Team Project
    • Level 3 Team Project
    • Level 3 Team Project
Powered by GitBook
On this page
  • Emoji Personality Test App
  • Overview
  • Step 1. Initialize the Project
  • Step 2. Project Structure
  • Step 3. Data Source (data/emojis.js)
  • 4. Styling (style.css)
  • Step 5. Main Logic (AppEmojiPersonality.jsx)
  • Main Logic (Step 5)
  • Step 6. Display Components
  • Explanation for Display Components (Step 6)
  • Step 7. Run & Test
  1. Final Term Project

Level 2 Team Project

PreviousLevel 2 Team ProjectNextLevel 3 Team Project

Last updated 1 month ago

Emoji Personality Test App

Overview

This guide walks you through building the Emoji Personality Test App using Vite with the React (JavaScript) template. By the end, you’ll understand how each part works and how to complete the handleClick function to move emojis between columns, track the count, and reveal results.

Step 1. Initialize the Project

  1. Create a new Vite app:

    npm create vite@latest emoji-personality-test -- --template react
  2. Install dependencies:

    cd emoji-personality-test
    npm install
    npm install nanoid
  3. Open your editor and confirm the generated files:

    • package.json, vite.config.js

    • src/ and data/ and components/ directory. If not created, create them now.


Step 2. Project Structure

emoji-personality-test/
├─ src/
│  ├ AppEmojiPersonality.jsx      # Main application logic
│  ├ style.css                   # App-wide styles
│  ├ data/
│  │   └ emojis.js               # Array of emoji strings
│  └ components/
│      ├ EmojiLists.jsx          # Displays Liked vs Unselected lists
│      └ ResultsModal.jsx        # Modal for final results
└─ public/
   └ index.html                  # HTML entry point

Step 3. Data Source (data/emojis.js)

  • Contains a default export: an array of hundreds of emoji strings.

  • Used by getRandomEmojis() to pick three at random each round.

// emojis.js
export default [
  "💘", "💝", "💖", /* … hundreds more … */ "😀", "😃", "😄"
]

4. Styling (style.css)

Key classes:

  • .wrapper: centers and sizes the app container

  • .overall-emojis-container: lays out the three buttons horizontally

  • .overall-emoji-lists-container: holds the two list columns

  • .individual-emoji-list-container: styles each column

  • .results-modal-container: full-screen overlay for results

No changes are needed here unless you want to customize visuals.

Adjusting Emoji Size in Lists

If your emoji list items overflow, reduce their font sizes in style.css:

/* Liked emojis (larger) */
.individual-emoji-list-container:first-of-type li {
  font-size: 30px;    /* was 45px */
}

/* Unselected emojis (smaller) */
.individual-emoji-list-container:last-of-type li {
  font-size: 20px;    /* was 25px */
  line-height: 40px;  /* adjust to match size */
}

Step 5. Main Logic (AppEmojiPersonality.jsx)

The following is the complete AppEmojiPersonality.jsx file with comments highlighting each part:

import React from 'react'
import ResultsModal from './components/ResultModal'
import EmojiLists from './components/EmojiLists'
import emojis from './data/emojis'
import { nanoid } from 'nanoid'
import './style.css'

export default function App() {
  // State to track emojis liked by the user
  const [likedEmojis, setLikedEmojis] = React.useState([])
  // State to track emojis the user didn't click
  const [passedEmojis, setPassedEmojis] = React.useState([])
  // Current set of three emojis to display
  const [currentEmojis, setCurrentEmojis] = React.useState(getRandomEmojis)
  // Control whether the results modal is shown
  const [showResults, setShowResults] = React.useState(false)
  // Control whether the final results are ready (after animation)
  const [resultsReady, setResultsReady] = React.useState(false)

  /**
   * handleClick — invoked when an emoji button is clicked.
   * 1. Add clicked emoji to likedEmojis.
   * 2. Add the other two emojis to passedEmojis.
   * 3. Refresh currentEmojis via getRandomEmojis().
   */
  function handleClick(event) {
    // Determine which emoji was clicked
    const clicked = event.target.innerText

    // 1️⃣ Add the clicked emoji to the end of likedEmojis array
    setLikedEmojis((prev) => [...prev, clicked])

    // 2️⃣ Collect the other two emojis and add them to passedEmojis
    const others = currentEmojis.filter((e) => e !== clicked)
    setPassedEmojis((prev) => [...prev, ...others])

    // 3️⃣ Generate three new random emojis for the next round
    setCurrentEmojis(getRandomEmojis)
  }

  /**
   * getRandomEmojis — returns an array of three random emojis
   * picked from the data/emojis.js array.
   */
  function getRandomEmojis() {
    function chooseRandomEmoji() {
      return emojis[Math.floor(Math.random() * emojis.length)]
    }
    return new Array(3).fill('').map(() => chooseRandomEmoji())
  }

  /** Show the results modal */
  function getResults() {
    setShowResults(true)
  }

  /** Reset all state for a new test */
  function reset() {
    setLikedEmojis([])
    setPassedEmojis([])
    setShowResults(false)
    setResultsReady(false)
  }

  // When showResults becomes true, start a timer to trigger the "resultsReady" state
  React.useEffect(() => {
    if (showResults) {
      setTimeout(() => {
        setResultsReady(true)
      }, 2000)
    }
  }, [showResults])

  // Utility to generate list items with unique keys
  function generateListItems(element) {
    return <li key={nanoid()}>{element}</li>
  }

  return (
    <div className="wrapper">
      {/* Counter showing how many emojis have been liked out of 10 */}
      <div className="results-counter">{likedEmojis.length} / 10</div>

      {/* Modal component for displaying final results */}
      <ResultsModal
        showResults={showResults}
        getResults={getResults}
        resultsReady={resultsReady}
        reset={reset}
        generateListItems={generateListItems}
        likedEmojis={likedEmojis}
      />

      <h1>Emoji Personality Test</h1>

      {/* Show three emoji buttons until 10 selections, then show Get Results */}
      {likedEmojis.length < 10 ? (
        <div className="overall-emojis-container">
          <button onClick={handleClick}>{currentEmojis[0]}</button>
          <button onClick={handleClick}>{currentEmojis[1]}</button>
          <button onClick={handleClick}>{currentEmojis[2]}</button>
        </div>
      ) : (
        !showResults && (
          <button className="get-results-button" onClick={getResults}>
            Get Results
          </button>
        )
      )}

      {/* Lists showing liked vs. passed emojis */}
      <EmojiLists
        likedEmojis={likedEmojis}
        passedEmojis={passedEmojis}
        generateListItems={generateListItems}
      />
    </div>
  )
}

Main Logic (Step 5)

  • State Initialization: Five useState hooks manage distinct parts of the UI:

    • likedEmojis and passedEmojis collect user choices over time.

    • currentEmojis holds the three emojis displayed each round, initialized by calling getRandomEmojis.

    • showResults and resultsReady control the flow and timing of the results modal.

  • Emojis Selection Flow (handleClick):

    1. Identify Clicked Emoji: using event.target.innerText.

    2. Update Liked List: appends the clicked emoji to the existing array (setLikedEmojis(prev => [...prev, clicked])).

    3. Update Passed List: filters out the clicked emoji and appends the remaining two (setPassedEmojis(prev => [...prev, ...others])).

    4. Next Round: refreshes currentEmojis by re-invoking getRandomEmojis, triggering a re-render with new choices.

  • Randomization (getRandomEmojis):

    • Chooses three emojis independently by randomly indexing into the imported emojis array.

    • Ensures every round offers fresh, unpredictable options.

  • Results Cycle:

    • Trigger: After 10 selections (reflected by likedEmojis.length), the Get Results button becomes visible.

    • Timing: Clicking it sets showResults true, and an effect hook starts a 2 s timer before marking resultsReady — enabling a simple "loading" animation via CSS.

  • Utility Helpers:

    • generateListItems ensures each list item has a unique key, preventing React warnings and enabling proper reconciliation.

Step 6. Display Components

components/EmojiLists.jsx

components/ResultsModal.jsx

// EmojiLists.jsx
export default function EmojiLists({
  likedEmojis,
  passedEmojis,
  generateListItems,
}) {
  return (
    <div className="overall-emoji-lists-container">
      <div className="individual-emoji-list-container">
        <h3>Liked Emojis</h3>
        <ul>{likedEmojis.map(generateListItems)}</ul>
      </div>
      <div className="individual-emoji-list-container">
        <h3>Unselected Emojis</h3>
        <ul>{passedEmojis.map(generateListItems)}</ul>
      </div>
    </div>
  )
}
// Some code
export default function ResultsModal({
  showResults,
  resultsReady,
  getResults,
  reset,
  likedEmojis,
  generateListItems,
}) {
  if (!showResults) return null
  return (
    <div className="results-modal-container">
      <div className="modal-inner-container bounce-top">
        {resultsReady ? (
          <ul>{likedEmojis.map(generateListItems)}</ul>
        ) : (
          <p onClick={getResults} className="get-results-button">
            Get Results
          </p>
        )}
        {resultsReady && (
            <>
            <p>You have a great personality! </p>
          <p onClick={reset} className="try-again-button">
            Try Again
          </p>
          </>
        )}
      </div>
    </div>
  )
}

Explanation for Display Components (Step 6)

  • Props-Driven Rendering:

    • Both EmojiLists and ResultsModal receive state and helper functions via props — keeping them stateless and reusable.

  • Conditional UI (ResultsModal):

    • Returns null until showResults is true.

    • Inside, it toggles between two states: a Get Results button (waiting on user click) and the final emoji list (once resultsReady is true), plus a Try Again button to reset.

  • Flex Layout:

    • <div className="overall-emoji-lists-container"> uses CSS flexboxes to lay out columns side by side.

    • Each <ul> wraps emojis with appropriate font sizes for visual hierarchy.

  • Separation of Concerns:

    • Core logic resides in the main App component; display-only components simply render based on props, simplifying testing and maintenance.

Display Components (Section 6)

  • Props-Driven Rendering:

    • Both EmojiLists and ResultsModal receive state and helper functions via props — keeping them stateless and reusable.

  • Conditional UI (ResultsModal):

    • Returns null until showResults is true.

    • Inside, it toggles between two states: a Get Results button (waiting on user click) and the final emoji list (once resultsReady is true), plus a Try Again button to reset.

  • Flex Layout:

    • <div className="overall-emoji-lists-container"> uses CSS flexboxes to lay out columns side by side.

    • Each <ul> wraps emojis with appropriate font sizes for visual hierarchy.

  • Separation of Concerns:

    • Core logic resides in the main App component; display-only components simply render based on props, simplifying testing and maintenance.


Step 7. Run & Test

  1. Start the dev server:

    npm run dev
  2. Interact with the three emojis.

  3. Observe:

    • Emojis move into the correct columns.

    • Counter increments from 0 → 10.

    • At 10, click Get Results, then Try Again to reset.

Output:

17KB
emojis.js