Fix Undefine Error in ReactJS Budget Allocation App

I keep getting an “undefined” error in my ReactJS budget allocation app, and it’s been driving me a little crazy! I’m trying to add a dropdown menu for selecting currencies, so when a user chooses an option, the currency should update accordingly. But every time I load the webpage, I keep hitting this “undefined” error. I’m not entirely sure what’s going wrong. I think it might have something to do with the way I’m dispatching the currency change, but I’m stuck and not sure how to fix it. Can anyone take a look at my code and point me in the right direction? I’d really appreciate any advice on what could be causing this!

Error Code:

code// App.js
import ReactJS from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';

import { AppProvider } from './context/AppContext';
import Budget from './components/Budget';
import ExpenseTotal from './components/ExpenseTotal';
import ExpenseList from './components/ExpenseList';
import AllocationForm from './components/AllocationForm';
import RemainingBudget from './components/Remaining';
import Currency from './components/Currency';

const App = () => {
return (
<AppProvider>
<div className='container'>
<h1 className='mt-3'>Company's Budget Allocation</h1>
<div className='row mt-3'>
<div className='col-sm'>
<Budget />
</div>
<div className='col-sm'>
<RemainingBudget />
</div>
<div className='col-sm'>
<ExpenseTotal />
</div>
<div className='col-sm'>
<Currency />
</div>
</div>
<h3 className='mt-3'>Allocation</h3>
<div className='row'>
<div className='col-sm'>
<ExpenseList />
</div>
</div>
<h3 className='mt-3'>Change allocation</h3>
<div className='row mt-3'>
<div className='col-sm'>
<AllocationForm />
</div>
</div>
</div>
</AppProvider>
);
};

export default App;

// Currency.js
import ReactJS, { useState, useContext, useEffect } from 'ReactJS';
import { AppContext } from '../context/AppContext';

const Currency = () => {
const [currency, setCurrency] = useState('');
const { dispatch } = useContext(AppContext);

const handleChange = (event) => {
setCurrency(event.target.value);
changeCurrency(event.target.value);
};

const changeCurrency = (selectedCurrency) => {
dispatch({
type: 'CHG_CURRENCY',
payload: selectedCurrency,
});
};

useEffect(() => {
console.log(currency);
}, [currency]);

return (
<div className="alert alert-secondary">
<select id="inputGroupSelect02" onChange={handleChange}>
<option defaultValue>Currency</option>
<option value="$" name="dollar">$ Dollar</option>
<option value="£" name="pound">£ Pound</option>
<option value="€" name="euro">€ Euro</option>
<option value="₹" name="rupee">₹ Rupee</option>
</select>
</div>
);
};

export default Currency;

This code demonstrates a basic budget allocation application built with ReactJS. The main objective is to provide a layout where users can manage budget allocations, including components for viewing the budget, tracking expenses, and selecting a currency type.

Solution Outline:

  1. App Structure: The main App component wraps the entire application in a AppProvider context, which shares state among child components.
  2. Components:
    • Budget: Displays and manages the total budget.
    • RemainingBudget: Shows the remaining budget after expenses.
    • ExpenseTotal: Calculates the total expenses.
    • ExpenseList: Lists all expenses.
    • AllocationForm: Allows adjustments in budget allocation.
    • Currency: Handles currency selection and updates the budget currency.
  3. Context Setup: AppContext manages global state, making it accessible to all components through the useContext hook.

Problem in the Code:

The main issue with the code is that changeCurrency() is called immediately after setCurrency in the handleChange function, leading to outdated values in the dispatch function. This is because setCurrency is asynchronous, and changeCurrency() doesn’t get the updated value of currency.

Correct Code:

code// App.js
import ReactJS from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';

import { AppProvider } from './context/AppContext';
import Budget from './components/Budget';
import ExpenseTotal from './components/ExpenseTotal';
import ExpenseList from './components/ExpenseList';
import AllocationForm from './components/AllocationForm';
import RemainingBudget from './components/Remaining';
import Currency from './components/Currency';

const App = () => {
return (
<AppProvider>
<div className='container'>
<h1 className='mt-3'>Company's Budget Allocation</h1>
<div className='row mt-3'>
<div className='col-sm'>
<Budget />
</div>
<div className='col-sm'>
<RemainingBudget />
</div>
<div className='col-sm'>
<ExpenseTotal />
</div>
<div className='col-sm'>
<Currency />
</div>
</div>
<h3 className='mt-3'>Allocation</h3>
<div className='row'>
<div className='col-sm'>
<ExpenseList />
</div>
</div>
<h3 className='mt-3'>Change allocation</h3>
<div className='row mt-3'>
<div className='col-sm'>
<AllocationForm />
</div>
</div>
</div>
</AppProvider>
);
};

export default App;

// Currency.js
import React, { useState, useContext, useEffect } from 'ReactJS';
import { AppContext } from '../context/AppContext';

const Currency = () => {
const [currency, setCurrency] = useState('');
const { dispatch } = useContext(AppContext);

const handleChange = (event) => {
const selectedCurrency = event.target.value;
setCurrency(selectedCurrency);
changeCurrency(selectedCurrency);
};

const changeCurrency = (selectedCurrency) => {
dispatch({
type: 'CHG_CURRENCY',
payload: selectedCurrency,
});
};

useEffect(() => {
console.log(currency);
}, [currency]);

return (
<div className="alert alert-secondary">
<select id="inputGroupSelect02" onChange={handleChange}>
<option defaultValue>Currency</option>
<option value="$" name="dollar">$ Dollar</option>
<option value="£" name="pound">£ Pound</option>
<option value="€" name="euro">€ Euro</option>
<option value="₹" name="rupee">₹ Rupee</option>
</select>
</div>
);
};

export default Currency;

Explanation of Changes:

  1. handleChange Adjustment:
    • handleChange now captures the selected currency value (event.target.value) in selectedCurrency and passes this directly to changeCurrency. This ensures that dispatch is called with the updated currency value immediately.
  2. useEffect:
    • useEffect logs the current currency whenever it changes, which is helpful for debugging.

This revised code structure improves performance and avoids potential bugs related to asynchronous state updates in ReactJS. The context setup and component structure enable smooth management and visibility of the budget allocation.

Related blog posts