8 React Projects for Building Your Skills

8 React Projects for Building Your Skills

Building React projects is a great way to improve your skills and gain practical experience. Here are ten project ideas that vary in complexity, allowing you to enhance your React proficiency gradually:

To-Do List app

Create a simple to-do list where users can add, edit, and mark tasks as completed. You can also add features like filtering, sorting, and storing tasks in local storage.

import React, { useState } from 'react';

const TodoApp = () => {
  const [tasks, setTasks] = useState([]);
  const [task, setTask] = useState('');

  const handleInputChange = (e) => {
    setTask(e.target.value);
  };

  const handleAddTask = () => {
    if (task.trim() !== '') {
      setTasks([...tasks, { text: task, completed: false }]);
      setTask('');
    }
  };

  const handleToggleComplete = (index) => {
    const updatedTasks = tasks.map((t, i) =>
      i === index ? { ...t, completed: !t.completed } : t
    );
    setTasks(updatedTasks);
  };

  const handleRemoveTask = (index) => {
    const updatedTasks = tasks.filter((t, i) => i !== index);
    setTasks(updatedTasks);
  };

  return (
    <div>
      <h1>To-Do List</h1>
      <div>
        <input
          type="text"
          value={task}
          onChange={handleInputChange}
          placeholder="Add a task..."
        />
        <button onClick={handleAddTask}>Add</button>
      </div>
      <ul>
        {tasks.map((t, index) => (
          <li key={index}>
            <input
              type="checkbox"
              checked={t.completed}
              onChange={() => handleToggleComplete(index)}
            />
            <span style={{ textDecoration: t.completed ? 'line-through' : 'none' }}>{t.text}</span>
            <button onClick={() => handleRemoveTask(index)}>Remove</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TodoApp;

To use this code, you'll need to set up a React project and create a component file (e.g., TodoApp.js) where you can paste this code. Then, you can import and use the TodoApp component in your main application file.

This code sets up a functional component TodoApp that maintains an array of tasks in its state using the useState hook. It provides input fields to add tasks, checkboxes to mark tasks as completed, and buttons to remove tasks.

Keep in mind that this is a basic example, and you can extend and customize it further based on your specific requirements.

Weather App

Build a weather application that fetches data from a weather API and displays the current weather conditions and forecasts for a specific location.

import React, { useState } from 'react';

const WeatherApp = () => {
  const [city, setCity] = useState('');
  const [weatherData, setWeatherData] = useState(null);

  const apiKey = 'YOUR_API_KEY'; // Replace with your own API key

  const fetchWeatherData = async () => {
    try {
      const response = await fetch(
        `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKey}`
      );

      if (!response.ok) {
        throw new Error('City not found');
      }

      const data = await response.json();
      setWeatherData(data);
    } catch (error) {
      alert(error.message);
    }
  };

  const handleInputChange = (e) => {
    setCity(e.target.value);
  };

  const handleSearch = () => {
    fetchWeatherData();
  };

  return (
    <div>
      <h1>Weather App</h1>
      <div>
        <input
          type="text"
          value={city}
          onChange={handleInputChange}
          placeholder="Enter city name"
        />
        <button onClick={handleSearch}>Search</button>
      </div>
      {weatherData && (
        <div>
          <h2>{weatherData.name}</h2>
          <p>{weatherData.weather[0].description}</p>
          <p>Temperature: {weatherData.main.temp}°C</p>
          <p>Humidity: {weatherData.main.humidity}%</p>
        </div>
      )}
    </div>
  );
};

export default WeatherApp;

Here's how the code works:

  1. We use the useState hook to manage the city input and the weather data.
  2. The fetchWeatherData function makes an API call to OpenWeatherMap to get weather data based on the provided city.
  3. The handleInputChange function updates the city state as the user types in the input field.
  4. When the user clicks the "Search" button, it triggers the handleSearch function which calls fetchWeatherData.
  5. If the API call is successful, the weather data is stored in the weatherData state.
  6. The component renders the input field, search button, and displays the weather information if available.

Remember to replace 'YOUR_API_KEY' with your actual API key from OpenWeatherMap. You can sign up on their website to get a free API key.

To use this code, you'll need to set up a React project and create a component file (e.g., WeatherApp.js) where you can paste this code. Then, you can import and use the WeatherApp component in your main application file.

Expense Tracker

Develop an application to track income and expenses. Allow users to add, edit, and delete transactions and display a summary of their financial activities.

Below is an example of a simple expense tracker app using React. This app allows users to add, edit, and delete transactions, and it displays a summary of their financial activities.

import React, { useState } from 'react';

const ExpenseTracker = () => {
  const [transactions, setTransactions] = useState([]);
  const [text, setText] = useState('');
  const [amount, setAmount] = useState('');

  const addTransaction = () => {
    if (text.trim() !== '' && !isNaN(Number(amount))) {
      const newTransaction = {
        id: Math.random(),
        text: text,
        amount: +amount
      };

      setTransactions([...transactions, newTransaction]);
      setText('');
      setAmount('');
    }
  };

  const deleteTransaction = (id) => {
    const updatedTransactions = transactions.filter((transaction) => transaction.id !== id);
    setTransactions(updatedTransactions);
  };

  const totalIncome = transactions.reduce((acc, transaction) => {
    return transaction.amount > 0 ? acc + transaction.amount : acc;
  }, 0);

  const totalExpense = transactions.reduce((acc, transaction) => {
    return transaction.amount < 0 ? acc + transaction.amount : acc;
  }, 0);

  return (
    <div>
      <h1>Expense Tracker</h1>
      <div>
        <input
          type="text"
          value={text}
          onChange={(e) => setText(e.target.value)}
          placeholder="Enter description"
        />
        <input
          type="number"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
          placeholder="Enter amount"
        />
        <button onClick={addTransaction}>Add Transaction</button>
      </div>
      <div>
        <h2>Transactions</h2>
        <ul>
          {transactions.map((transaction) => (
            <li key={transaction.id}>
              {transaction.text} - {transaction.amount}{' '}
              <button onClick={() => deleteTransaction(transaction.id)}>Delete</button>
            </li>
          ))}
        </ul>
      </div>
      <div>
        <h2>Summary</h2>
        <p>Total Income: {totalIncome}</p>
        <p>Total Expense: {totalExpense}</p>
        <p>Balance: {totalIncome + totalExpense}</p>
      </div>
    </div>
  );
};

export default ExpenseTracker;

In this example:

  1. We use the useState hook to manage the state of transactions, text input, and amount input.
  2. The addTransaction function adds a new transaction to the list if both the description (text) and amount are valid.
  3. The deleteTransaction function filters out the transaction with the specified ID to remove it from the list.
  4. The totalIncome and totalExpense variables calculate the sums of income and expenses, respectively.
  5. The component renders input fields for description and amount, a button to add a transaction, a list of transactions, and a summary section.

You can create a new component file (e.g., ExpenseTracker.js) in your React project, paste this code, and then import and use the ExpenseTracker component in your main application file.

Feel free to modify and extend this code to suit your specific requirements!

E-commerce Storefront

Design a basic e-commerce site with features like product listings, search, product details, and a shopping cart. You can also implement user authentication and a checkout process.

Creating a full-fledged e-commerce storefront involves a lot of components and features, so I'll provide a simplified example to get you started. This example will include product listings, a shopping cart, and basic functionality to add and remove items.

import React, { useState } from 'react';

const Product = ({ product, onAddToCart }) => {
  return (
    <div className="product">
      <h3>{product.name}</h3>
      <p>Price: ${product.price}</p>
      <button onClick={() => onAddToCart(product)}>Add to Cart</button>
    </div>
  );
};

const CartItem = ({ item, onRemoveFromCart }) => {
  return (
    <div className="cart-item">
      <span>{item.name}</span>
      <span>Quantity: {item.quantity}</span>
      <button onClick={() => onRemoveFromCart(item)}>Remove</button>
    </div>
  );
};

const EcommerceStorefront = () => {
  const [products] = useState([
    { id: 1, name: 'Product A', price: 10 },
    { id: 2, name: 'Product B', price: 20 },
    { id: 3, name: 'Product C', price: 30 },
  ]);

  const [cart, setCart] = useState([]);

  const handleAddToCart = (product) => {
    const existingItem = cart.find((item) => item.id === product.id);

    if (existingItem) {
      const updatedCart = cart.map((item) =>
        item.id === product.id ? { ...item, quantity: item.quantity + 1 } : item
      );
      setCart(updatedCart);
    } else {
      setCart([...cart, { ...product, quantity: 1 }]);
    }
  };

  const handleRemoveFromCart = (item) => {
    const updatedCart = cart.filter((cartItem) => cartItem.id !== item.id);
    setCart(updatedCart);
  };

  return (
    <div>
      <h1>E-commerce Storefront</h1>
      <div className="products">
        {products.map((product) => (
          <Product key={product.id} product={product} onAddToCart={handleAddToCart} />
        ))}
      </div>
      <div className="cart">
        <h2>Shopping Cart</h2>
        {cart.map((item) => (
          <CartItem key={item.id} item={item} onRemoveFromCart={handleRemoveFromCart} />
        ))}
      </div>
    </div>
  );
};

export default EcommerceStorefront;

In this example:

  1. We have a Product component that displays the name, price, and an "Add to Cart" button for a given product.
  2. We also have a CartItem component that displays the name, quantity, and a "Remove" button for an item in the shopping cart.
  3. The EcommerceStorefront component manages the list of products and the shopping cart using the useState hook.
  4. The handleAddToCart function adds items to the cart, updating the quantity if the item already exists.
  5. The handleRemoveFromCart function removes items from the cart.

Please note that this is a simplified example and doesn't include features like authentication, actual product images, payment processing, or routing. In a real-world application, you would need to implement these and other features to create a complete e-commerce storefront.

Blog Platform

Create a blogging platform where users can register, create, edit, and delete posts. Implement features like user authentication and authorization.

Creating a full-fledged blog platform is a complex task that involves many components and features. I'll provide a simplified example to get you started. This example will include basic functionality to create, edit, and delete blog posts.

import React, { useState } from 'react';

const BlogPost = ({ post, onDelete }) => {
  return (
    <div className="blog-post">
      <h2>{post.title}</h2>
      <p>{post.content}</p>
      <button onClick={() => onDelete(post.id)}>Delete</button>
    </div>
  );
};

const BlogPlatform = () => {
  const [posts, setPosts] = useState([]);
  const [title, setTitle] = useState('');
  const [content, setContent] = useState('');

  const addPost = () => {
    if (title.trim() !== '' && content.trim() !== '') {
      const newPost = {
        id: Date.now(),
        title: title,
        content: content
      };

      setPosts([...posts, newPost]);
      setTitle('');
      setContent('');
    }
  };

  const deletePost = (id) => {
    const updatedPosts = posts.filter((post) => post.id !== id);
    setPosts(updatedPosts);
  };

  return (
    <div>
      <h1>Blog Platform</h1>
      <div>
        <input
          type="text"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          placeholder="Enter post title"
        />
        <textarea
          value={content}
          onChange={(e) => setContent(e.target.value)}
          placeholder="Write your post here"
        />
        <button onClick={addPost}>Add Post</button>
      </div>
      <div className="blog-posts">
        {posts.map((post) => (
          <BlogPost key={post.id} post={post} onDelete={deletePost} />
        ))}
      </div>
    </div>
  );
};

export default BlogPlatform;

In this example:

  1. We have a BlogPost component that displays the title, content, and a "Delete" button for a blog post.
  2. The BlogPlatform component manages the list of posts using the useState hook.
  3. The addPost function adds a new post to the list if both the title and content are valid.
  4. The deletePost function removes a post from the list.

Please note that this is a simplified example and doesn't include features like authentication, user accounts, database integration, or rich text editing. In a real-world application, you would need to implement these and other features to create a complete blog platform.

GitHub Repository Viewer

Build a tool that allows users to search for GitHub repositories and view details like stars, forks, and contributors. Utilize the GitHub API for data retrieval.

Creating a GitHub Repository Viewer involves integrating with the GitHub API to fetch and display repository information. Here's a simplified example using React:

import React, { useState } from 'react';

const GitHubRepoViewer = () => {
  const [username, setUsername] = useState('');
  const [repositories, setRepositories] = useState([]);
  const [error, setError] = useState(null);

  const fetchRepositories = async () => {
    try {
      const response = await fetch(`https://api.github.com/users/${username}/repos`);

      if (!response.ok) {
        throw new Error('User not found');
      }

      const data = await response.json();
      setRepositories(data);
      setError(null);
    } catch (error) {
      setError(error.message);
      setRepositories([]);
    }
  };

  return (
    <div>
      <h1>GitHub Repository Viewer</h1>
      <div>
        <input
          type="text"
          value={username}
          onChange={(e) => setUsername(e.target.value)}
          placeholder="Enter GitHub username"
        />
        <button onClick={fetchRepositories}>Get Repositories</button>
      </div>
      {error && <div style={{ color: 'red' }}>{error}</div>}
      <ul>
        {repositories.map((repo) => (
          <li key={repo.id}>
            <a href={repo.html_url} target="_blank" rel="noopener noreferrer">
              {repo.name}
            </a>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default GitHubRepoViewer;

In this example:

  1. We have a GitHubRepoViewer component that allows users to input a GitHub username and fetch their repositories.
  2. The fetchRepositories function makes an API call to GitHub's API to retrieve the list of repositories for the given username.
  3. If an error occurs during the API call (e.g., user not found), it updates the error state to display an error message.
  4. The component renders an input field, a "Get Repositories" button, and a list of repositories.

Please note that you might need to handle pagination if a user has many repositories. Additionally, you should handle loading states and potentially add additional features like searching or sorting repositories.

Remember also to consider handling edge cases and potential errors during the API call.

Recipe Finder

Develop an application that allows users to search for recipes based on ingredients they have. Integrate with a recipe API to fetch and display results.

Creating a Recipe Finder app involves integrating with a recipe API to search and display recipes. Here's a simplified example using React:

import React, { useState } from 'react';

const RecipeFinder = () => {
  const [ingredient, setIngredient] = useState('');
  const [recipes, setRecipes] = useState([]);
  const [error, setError] = useState(null);

  const fetchRecipes = async () => {
    try {
      const response = await fetch(`https://api.spoonacular.com/recipes/findByIngredients`, {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json'
        },
        params: {
          apiKey: 'YOUR_API_KEY', // Replace with your own API key
          ingredients: ingredient,
          number: 5 // Number of recipes to fetch
        }
      });

      if (!response.ok) {
        throw new Error('Error fetching recipes');
      }

      const data = await response.json();
      setRecipes(data);
      setError(null);
    } catch (error) {
      setError(error.message);
      setRecipes([]);
    }
  };

  return (
    <div>
      <h1>Recipe Finder</h1>
      <div>
        <input
          type="text"
          value={ingredient}
          onChange={(e) => setIngredient(e.target.value)}
          placeholder="Enter ingredient (e.g., chicken, onion)"
        />
        <button onClick={fetchRecipes}>Find Recipes</button>
      </div>
      {error && <div style={{ color: 'red' }}>{error}</div>}
      <ul>
        {recipes.map((recipe) => (
          <li key={recipe.id}>
            <h3>{recipe.title}</h3>
            <img src={recipe.image} alt={recipe.title} />
          </li>
        ))}
      </ul>
    </div>
  );
};

export default RecipeFinder;

In this example:

  1. We have a RecipeFinder component that allows users to input an ingredient and fetch recipes.
  2. The fetchRecipes function makes an API call to the Spoonacular API to retrieve recipes based on the entered ingredient.
  3. If an error occurs during the API call, it updates the error state to display an error message.
  4. The component renders an input field, a "Find Recipes" button, and a list of recipes with their titles and images.

Please note that you'll need to obtain an API key from the Spoonacular API and replace 'YOUR_API_KEY' with it.

Remember that you might need to handle pagination or implement additional features like sorting or filtering the recipes. Also, consider handling loading states for a smoother user experience.

Chat Application

Create a real-time chat application using technologies like Firebase for the backend. Users should be able to join different chat rooms or create private messages.

Creating a real-time chat application in React involves using a backend service, like Firebase or a WebSocket server, for handling real-time communication. Here's a simplified example using Firebase for the backend:

Step 1: Set Up a New React App

npx create-react-app ${APP_NAME}

Step 2: Set Up Firebase

  • Go to the Firebase Console and create a new project.
  • Set up Firebase Authentication and Firestore database.
  • In your Firebase project, go to Project Settings > General > Your apps and click on the Web app (</>) to get your Firebase configuration.

Step 3: Install Firebase in Your React App

npm install firebase

Step 4: Create the Chat App Component

import React, { useState, useEffect } from 'react';
import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';

const firebaseConfig = {
  // Your Firebase configuration here
};

firebase.initializeApp(firebaseConfig);

const ChatApp = () => {
  const [messages, setMessages] = useState([]);
  const [text, setText] = useState('');

  const sendMessage = async () => {
    if (text.trim() !== '') {
      await firebase.firestore().collection('messages').add({
        text: text,
        timestamp: firebase.firestore.FieldValue.serverTimestamp(),
      });
      setText('');
    }
  };

  useEffect(() => {
    const unsubscribe = firebase.firestore().collection('messages').orderBy('timestamp').onSnapshot(snapshot => {
      const newMessages = snapshot.docs.map(doc => ({
        id: doc.id,
        ...doc.data()
      }));
      setMessages(newMessages);
    });

    return () => unsubscribe();
  }, []);

  return (
    <div>
      <h1>Chat App</h1>
      <div>
        <ul>
          {messages.map(message => (
            <li key={message.id}>{message.text}</li>
          ))}
        </ul>
      </div>
      <div>
        <input
          type="text"
          value={text}
          onChange={(e) => setText(e.target.value)}
          placeholder="Type a message..."
        />
        <button onClick={sendMessage}>Send</button>
      </div>
    </div>
  );
};

export default ChatApp;

Step 5: Use the Chat App Component

In your main application file (e.g., App.js), import and use the ChatApp component.

import React from 'react';
import ChatApp from './ChatApp';

function App() {
  return (
    <div className="App">
      <ChatApp />
    </div>
  );
}

export default App;

Remember to replace firebaseConfig with your actual Firebase configuration obtained from the Firebase Console.

Please note that this is a very basic example and lacks user authentication and more advanced features. In a real-world application, you would implement user authentication, handle user-specific messages, and potentially integrate more complex features like message history, user profiles, and more.