This guide provides a step-by-step procedure to build a Stock Tracker application using React and Vite, with dynamically-generated stock data. College students can follow along to implement and understand each part of the app.
1. Prerequisites
Node.js and npm installed on your machine.
Basic knowledge of React (components, props, state, hooks).
A code editor (e.g., VS Code).
2. Project Setup
Initialize a new Vite + React project:
npm create vite@latest stock-tracker-app -- --template react
cd stock-tracker-app
npm install
npm run dev
Use the provided CSS to layout the grid, color-code changes, and style your app. Ensure your className attributes match those in the CSS (e.g., .green, .red, .stock-container).
Place your SVG files in src/images/ and reference them with relative paths in stockData.js and App.jsx.
8. Run & Test
Start development server: npm run dev
Openhttp://localhost:5173 in your browser.
Verify:
Stock cards render dynamically from stockData.js.
Numeric and percentage changes update correctly.
Color and arrows reflect gains, losses, or no change.
Live price updates (if implemented).
Output:
9. Improve App
We noted that prevClosingPrice is not updated at every 4 sec as currentPrice is updated. Let's improve the code by modifying App.jsx and Stock.jsx to reflect the change accordingly.
To ensure that prevClosingPrice is properly synchronized with currentPrice and can be updated accordingly, you need to modify both App.jsx and Stock.jsx. Here's how you can do it:
App.jsx
Initialize prevData with the same data as currentData initially.
Update prevData every time currentData is updated.
Here's the modified App.jsx:
// updated src/App.jsx
import React from 'react'
import stockData from './data/stockData'
import Stock from './components/Stock'
import './style.css'
export default function App() {
const [currentData, setCurrentData] = React.useState(stockData)
const [prevData, setPrevData] = React.useState(stockData) // Initialize with the same data as currentData
React.useEffect(() => {
const id = setInterval(() => {
const updatedData = currentData.map((s) => ({
...s,
currentPrice: +(
Math.random() > 0.5
? s.currentPrice + Math.random() * 20
: s.currentPrice - Math.random() * 20
).toFixed(2),
}))
setPrevData(currentData) // Update prevData before updating currentData
setCurrentData(updatedData)
}, 4000)
return () => clearInterval(id)
}, [currentData]) // Dependency on currentData to ensure it updates correctly
return (
<div>
<header>
<img className="app-logo" src="src/images/app-logo.svg" alt="Logo" />
<h1>
<span>Stock Tracker App</span>
</h1>
</header>
<div className="wrapper">
{currentData.map((stock, index) => (
<Stock
key={stock.stockName}
stock={stock}
prevStock={prevData[index]}
/>
))}
</div>
</div>
)
}
Explanation
App.jsx:
prevData is initialized with the same data as currentData.
Every 4 seconds, prevData is updated to the current currentData before currentData is updated with new random prices.
The Stock component is now passed both stock and prevStock as props.
Stock.jsx
Accept prevStock as a prop to get the previous stock data.
Calculate the numericalChange and rateChange using both currentPrice and prevClosingPrice.