Search code examples
javascriptreactjsreact-hooksuse-reduceruse-context

TypeError: Cannot read property 'map' of undefined - React app - useContext and useReducer issue


I am using react for making an app project using contextHook and reducerHook but getting:

TypeError: Cannot read property 'map' of undefined

The same code was working a few days back, but now it's giving that error. I've wasted so many hours trying to finding answers on the internet, but I couldn't get any help... Here are pictures of the error and my code as well:

Complete code on Github repo

Error Pic 1

Error Pic 2

Error Pic 3

//App.js

import React from 'react';

import './App.css';

import Header from './Header';
import Balance from './Balance';
import AccSummary from './AccSummary';
import TransactionHistory from './Transactionhistory';
import AddTransaction from './AddTransaction';


function App() {
  return (
    <div className='container'>
      <Header />
      <Balance />
      <AccSummary />
      <TransactionHistory />
      <AddTransaction />
      </div>
      
  );
}

export default App;


//Transaction.js

import React from 'react';

export const Transaction = ({transObj}) => { 
    return (
        <li>
            <span>{transObj.description}</span>
            <span> {transObj.amount} </span>
          </li>
    )
}

//TransactionHistory.js

import React, { useContext } from 'react';
import { TransactionContext } from './TransContext';
import { Transaction } from './Transaction';

function TransactionHistory() {
  

  let  {transactions}  = useContext(TransactionContext);
  return (
    <div>
      <h2> History </h2>
      <hr />
      <ul className='transaction-list'>
        {transactions.map(transObj => (
          <Transaction key={transactions.id} transactions = {transactions} />
        ))}
        
//Add Transaction.js

import React from 'react';

function AddTransaction() {
  return (
    <div>

    <h2 className='AddTrans'> <br /> Add New Transaction</h2>
    <hr />
    <form className = 'transaction-form'>
      <label>
        Enter Description <br />
        <input type='text'
        placeholder='Enter Detail of Transaction' className='color'/> <br />
      </label>

      <label>
        Enter Amount <br />
        <input type='Number'
        placeholder='Enter Transaction Amount'/>
      </label>
      <br />
      <input className='button' type="submit" value="Add Transaction"/>

    </form>
    </div>
  );
}

export default AddTransaction;


//TransContezt.js

import { createContext } from "react";

const initialTransaction = [
    {amount: 500, description: 'Cash'},
    {amount: -200, description: 'Bill'}
]

export const TransactionContext = createContext(initialTransaction);
//App.css

.container {
  width: 350px;
  min-height: 700px;
  margin: 0 auto ;
  background-color:white;
  
  box-shadow: 0 0 10px gray;
  margin-top: 50px;
  padding: 10px 50px;
  font-family: "Times New Roman", Times, serif;
  background-image: url("1.png"), url("2.png"), url("3.png"), url("4.png");
  background-position: left top, left top, left top, left top ;
  background-repeat: repeat-x;
  background-size: 100% 20%, 100% 55%, 100% 75%, 100% 100%;
  
}

.text-centre{
  text-align: center;
  justify-content: space-between;
  
  background-color: #98DBC6;
  border-radius: 5px;
  display: grid;
  justify-content: space-around;
  
  
}

.accsumm{
  display: flex;
  justify-content: space-around ;
  background-color: #5BC8AC;
  box-shadow:  0 0 10px gray;
  border: thin;
  font-family: Arial, Helvetica, sans-serif;
  border-radius: 5px;

}

.AddTrans{
  margin: 10px 0 0;

}

.transaction-form input{
  width: 97%;
  margin: 10px 0;
  
  padding: 15px 5px;
  border-radius: 5px;
  
  color: white;
}

.color{
  color: white;
}

.transaction-list{
  margin: 0;
  padding: 0; 
  
}
.transaction-list > li{
  display: flex;
  justify-content: space-between;
  box-shadow: 0 0 10px gray;
  padding: 10px 5px;
  background-color: honeydew;
  margin: 5px 0;
  border-radius: 5px;
}

.button {
  
  width: 100%;
  display: flex;
  justify-content: space-around;
  box-shadow: 0 0 10px gray;
  padding: 10px 10px;
  background-color: rgb(138, 179, 255);
  margin: 10px 0;
  border-radius: 5px;
  font-size: larger;
  font-weight: bolder;
  align-self: center;
}
Tr


Solution

  • For the TransactionHistory component:

    1. The default context value is an array but you destructure it like an object.
    2. In the mapping function, you are passing the original array as a prop instead of the element.

    Here is an updated version:

    function TransactionHistory() {
      const transactions = useContext(TransactionContext);
      return (
        <div>
          <h2> History </h2>
          <hr />
          <ul className="transaction-list">
            {transactions.map((transObj, index) => (
              <Transaction key={index} transaction={transObj} />
            ))}
          </ul>
        </div>
      );
    }
    

    Then, in the Transaction component, it is expecting transObj prop but its parent passes in transaction prop. So you might fix it as well:

    import React from "react";

    const Transaction = ({ transObj }) => {
      return (
        <li>
          <span>{transObj.description}</span>
          <span> {transObj.amount} </span>
        </li>
      );
    };