Skip to content

jamcmich/google-search-clone

Repository files navigation

Google Icon

Google Search Clone

A static web application that uses Google’s search engine to render results.

DemoFeaturesTechnologies UsedScreenshotsProblem SolvingCode ExamplesFuture Improvements

🔍 Demo

https://jamcmich.github.io/google-search-clone/

✨ Features

Note: This website has identical elements and styling to Google's search page but includes only the essential search features.

  • Search functionality with Google via RapidAPI
  • Responsive styling for mobile, tablet, and desktop
  • Data fetching and theme switcher via Higher Order Components
  • Custom tooltip system

🧰 Technologies Used

JavaScript NodeJS React React Router Axios Vite WindiCSS

👀 Screenshots

🚧 Problem Solving

Styling Conventions

This project was my first exposure to using WindiCSS (an on-demand alternative to Tailwind). Although Windi is convenient for styling elements on the fly, it suffers from the same issues as Tailwind: lack of legibility, inability to chain selectors, cluttering the DOM, etc. I realized the need for a consistent naming scheme after styling my first few React components and began researching a flexible solution.

After looking into the issue, I discovered a CSS naming convention created by BEM for writing cleaner and more readable class names. You can read up on the methodology with examples in BEM's official guide. These practices provided me with solutions for simplifying the DOM structure, creating descriptive CSS styles, and self-documenting my code.

Reading up on the Windi documentation allowed me to incorporate Windi's utility classes in an external stylesheet and preserve my application's class naming schemes. Even though this method would invalidate one of the framework's biggest advantages, I was able to reduce the clutter of my JSX files and create a solution with BEM conventions in mind.

Custom Tooltips

Since React is a very flexible library, many developers turn to third-party solutions when it comes to certain features. For example, some components on Google's search page provide users with tooltips on hover and I needed a way to incorporate this functionality into my project.

React Tooltip is a library with almost 3k stars on GitHub. Many developers rely on external solutions such as this one assuming the library will be well maintained and up-to-date. Unfortunately, myself and many others were running into compatibility issues between React Tooltip and React 18. The repository had been struggling to find a maintainer and likely wouldn't be updated for the new version of React anytime soon.

I decided to create a simple, reusable tooltip system that complimented my project instead of relying on the inconsistencies of an external library. This solution was lightweight and allowed me to wrap icons within my <Tooltip /> component and create custom tooltip styles.

Data Fetching

For this application, we only need to service GET requests from the API. Fetching data in React is fairly straightforward using Async/Await and Axios (see Data Fetching code snippet). The real challenge is distributing the returned data across a React project between parent and child components. To overcome this obstacle we can use React Context.

React Context

The React Context API was introduced in React v16.3, allowing developers to pass data through component trees and share information at various levels in an application. Instead of passing props down through every single component on the tree, the components that require a prop can simply request it from useContext(). This feature circumvents the dreaded practice of prop drilling and reduces unnecessary re-rendering.

To use Context within our application we first establish a State Provider, essentially a higher order component that passes values to it's {children}, to use state within our application. Feel free to view my implementation of StateContext here for a better understanding. You might notice that my code includes an additional implementation useReducer() which is an alternative to useState() and is used when the next state depends on the previous one. This allows us to implement features such as comparing form inputs or toggling themes.

Reducer

I used React's reducer hook in conjunction with React Context to reference search inputs and the application's current theme. useReducer() works exactly like JavaScript's Array reduce() function by receiving an initial value of state and an action, and then returning a new state. I created two actionTypes within my application, SET_SEARCH_INPUT and SET_APPLICATION_THEME, to pass input and theme values to various components (see Reducer code snippet).

Data Rendering

Data is rendered to the virtual DOM by mapping over results fetched from the GET method in useSearch.js.

Theme Switching

React Context makes it easy to receive, mutate, and pass the global state value of theme to any component. In this example with the application's theme switching feature, I use the theme state to conditionally render icons and toggle between styles pertaining to light and dark mode.

Parsing Search Input

Search engines are built with varying degrees of complexity to allow for detailed queries. Most users take advantage of basic keyword searching so I decided to implement a regex pattern that combines words and filters special characters.

For example, searching cat memes or cat!@#$%-_memes is parsed to cat+memes which is the appropriate format for Google's search engine parameters. The resulting URL becomes https://google-search3.p.rapidapi.com/api/v1/search/q=cat+memes&num=10.

Continuous Integration

This project was my first exposure to GitHub Actions. After reading about the benefits of continuous integration and development, I decided to create a workflow that would build and deploy my project to GitHub Pages automatically.

Webpack Configuration

A neat trick I learned throughout the development of this project is using Webpack aliases to create shortened file references. This is extremely helpful for avoiding long and repetitive path names such as import ModuleName from '../../../src/components/Component. See the Webpack Configuration code snippet for more details.

📸 Code Examples

Styling Conventions

Custom Tooltips

Data Fetching

React Context

State Provider

Reducer

Data Rendering

Theme Switching

Parsing Search Input

Continuous Integration

Webpack Configuration

🧪 Future Improvements

  • Pagination
  • "I'm Feeling Lucky" button takes the user to a random page
  • Sorting results into sections (i.e. All, Images, News, etc.)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published