Errors Unhandled Rejection & Objects are not valid as a React child

Hey @nadtn

Check your cloud function, it doesnā€™t return ETH balance - thatā€™s why it shows NaN.
The repo you shared doesnā€™t have Transactions.jsx and works without any bugs.

In the repo wasnā€™t updated (that was the last working version), can you please check now?
Canā€™t test since I have errors but changed:

  const balQuery = new Moralis.Query("_EthAddress");
  balQuery.equalTo("objectId", userAddress);
  const balResult = await balQuery.first({useMasterKey: true});

  results.push({
    name: "Ethereum",
    symbol: "ETH",
    balance: balResult.get("EthBalance"),
    decimals: 18
  });

To

  const balQuery = new Moralis.Query("EthAddress");
  balQuery.equalTo("address", userAddress);
  const balResult = await balQuery.first({useMasterKey: true});

  results.push({
    name: "Ethereum",
    symbol: "ETH",
    balance: balResult.get("balance"),
    decimals: 18
  });

Saved in the cloud functions section in the server, I donā€™t know when itā€™ll be updated in my project or do I have to do it manually?

What I changed in the cloud function created an error. Iā€™ll let you check first with the old one then Iā€™ll look into the new one

The component name should match the name of the exported function:

You need to use:
export default function Transactions(date)
Instead of:
export default async function setDivDate(date)

Itā€™s a bad practise to return async component like you did. All async logic should be outside component fucntion .

I suggest you to use accredited names for useState() hooks:
Correct:
const [name,setName] = useState()
const [date, setDate] = useState();
Not Correct:
const [valueDate, onChange] = useState();

I spent a very long time working on your code, but it has a lot of errors. I suggest you learn React with something simpler. Make a to-do for example.

Just spend a couple of days studying the React itself :man_factory_worker:

Your cloud fucntion should be like:

// this goes in the Moralis server Cloud Functions section
Moralis.Cloud.define("getTokens", async(request) => {
  const {userAddress} = request.params;
  if (!userAddress){
    return [];
  }
  
  const tokenQuery = new Moralis.Query("EthTokenBalance");
  tokenQuery.equalTo("address", userAddress);
  const tokenResult = await tokenQuery.find();
  
  const results = tokenResult.map((token) => token.attributes);
  
  const balQuery = new Moralis.Query("EthBalance");
  balQuery.equalTo("address", userAddress);
  const balResult = await balQuery.first({useMasterKey: true});

  results.push({
    name: "Ethereum",
    symbol: "ETH",
    balance: balResult.get("balance"),
    decimals: 18
  });
  
  return results;
});

You need to query the EthBalance table isntead of _EthAddress

Ok I took into consideration your remarks, this is the new Transaction.jsx

import React, { useEffect, useState } from "react";
import pageflip from "../data/pageflip.mp3";
import { Moralis } from "moralis";

async function getTransactions (date) {

    console.log("date in getTransactions: " + date)
    // set lessThan date
    let nextDate = new Date(date);
    nextDate.setDate(nextDate.getDate()+1);
                
    let query = new Moralis.Query('EthTransactions')
    query.greaterThan("block_timestamp", date);
    query.lessThan("block_timestamp", nextDate);
    const resultDateTransaction = await query.find()

    return resultDateTransaction;
  }

function millisecondsToTime (ms) {
    let minutes = Math.floor(ms / (1000 * 60));
    let hours = Math.floor(ms / (1000 * 60 * 60));
    let days = Math.floor(ms / (1000 * 60 * 60 * 24));
    
    if (days < 1) {
        if (hours < 1) {
            if (minutes < 1) {
                return `less than a minute ago`
            } else return `${minutes} minutes(s) ago`
        } else return `${hours} hours(s) ago`
    } else return `${days} days(s) ago`
  }

  const pageflipAudio = new Audio(pageflip);
  const playSound = audioFile => {
    audioFile.play();
}


export default function Transactions ({date}) {


    const resultDateTransaction = getTransactions (date);

    if (resultDateTransaction.length > 0) {

    return (
      <table border = "1" bordercolor = "blue">
      <caption>${resultDateTransaction.length} transaction(s) ${date.toLocaleDateString()}</caption>
      <thead>
      <tr>
      <th scope="col">Transaction</th>
      <th scope="col">Block Number</th>
      <th scope="col">Age</th>
      <th scope="col">Type</th>
      <th scope="col">Fee</th>
      <th scope="col">Value</th>
      <th scope="col">Notes</th>
          </tr>
      </thead>
      <tbody>
      {resultDateTransaction.forEach((t) => {
    return (
    <tr>
        <td><a href='https://etherscan.io/tx/${t.attributes.hash}' target="_blank" rel="noopener noreferrer">${t.attributes.hash}</a></td>
        <td><a href='https://etherscan.io/block/${t.attributes.block_number}' target="_blank" rel="noopener noreferrer">${t.attributes.block_number}</a></td>
        <td>${millisecondsToTime(Date.parse(new Date()) - Date.parse(t.attributes.block_timestamp))}</td>
        <td>${t.attributes.from_address == Moralis.User.current().get('ethAddress') ? 'Outgoing' : 'Incoming'}</td>
        <td>${((t.attributes.gas * t.attributes.gas_price) / 1e18).toFixed(5)} ETH</td>
        <td>${(t.attributes.value / 1e18).toFixed(5)} ETH</td>
        <td><input type="text" id="name" name="name"></input><button>Save</button></td>
    </tr>
    );
})}
      </tbody>
      </table>
    );

    playSound(pageflipAudio);

}
}

Works fine I guess.
But I still get


Iā€™ve also changed the cloud function like you said (the same as I suggested).
I donā€™t get why the errors says Transactions and points to coinDataā€¦ Is a default needed for Transactions?

But yes itā€™s my first time using React, thought I would learn while building but Iā€™ll definitely go back to the basics after the ETHOnline ends. Iā€™m also thinking of integrating the academy. :wink:

I guess this happens because of this:
if (resultDateTransaction.length > 0) { }
You always need to return something for render from the component.

So make something like:

export default function Transactions({ date }) {
        if (resultDateTransaction.length > 0) {
          return <>Your code</>;
        } else {
          return <>Loading</>;
        }
      }

The default I was mentioning, I get it, it works.
But now that I have my async logic outside the component:

export default function Transactions ({date}) {


    const resultDateTransaction = getTransactions (date);
    console.log("Transactions: " + resultDateTransaction)
    console.log("Transactions lengh: " + resultDateTransaction.length)
    
    if (resultDateTransaction.length > 0) {

I have this result:
Transactions: [object Promise]
Transactions lengh: undefined

But inside getTransactions I have:
Transactions in getTransactions: [object Object],[object Object]

Why am I not having the same value? Promise is for async right?

const resultDateTransaction = await query.find()


    if (resultDateTransaction.length > 0) {

You are trying to get length of the promise

I suggest you to create new hook for the query. As an example you can use useCoinData

So the logic will be quite simple. If it is fetching you return [] when it is fetched you return an array with objects

I didnā€™t get it, can you elaborate?
Tried like you said

export default function Transactions ({date}) {


    const resultDateTransaction = useTransactionsData (date);
    console.log("Transactions: " + resultDateTransaction)
    console.log("Transactions lengh: " + resultDateTransaction.length)

And this is transactionsData.js


import { Moralis } from "moralis";

export const useTransactionsData = (date) => {

    console.log("date in getTransactions: " + date)
    // set lessThan date
    let nextDate = new Date(date);
    nextDate.setDate(nextDate.getDate()+1);
                
    let query = new Moralis.Query('EthTransactions')
    query.greaterThan("block_timestamp", date);
    query.lessThan("block_timestamp", nextDate);
    const resultDateTransaction = query.find()

    console.log("Transactions in get: " + resultDateTransaction)

    return resultDateTransaction;
  };

With same result:

just noticed this:

=>
const resultDateTransaction = await query.find()

True thanks CK!
Because I had this I removed it:


Tried to add async but didnā€™t work. Not used to it to tell you the truth.

You can find an example with async await here: React Error: You need to call Parse.initialize before using Parse

Thanks so here we go:

import { Moralis } from "moralis";

export const useTransactionsData = async (date) => {

    // set lessThan date
    let nextDate = new Date(date);
    nextDate.setDate(nextDate.getDate()+1);
                
    let query = new Moralis.Query('EthTransactions')
    query.greaterThan("block_timestamp", date);
    query.lessThan("block_timestamp", nextDate);
    const resultDateTransaction = await query.find()

    console.log("Transactions in get: " + resultDateTransaction)

    return resultDateTransaction;
  };

But I still get [object Promise] in resultDateTransaction

export default function Transactions ({date}) {


    const resultDateTransaction = useTransactionsData (date);
    console.log("Transactions: " + resultDateTransaction)
    console.log("Transactions lengh: " + resultDateTransaction.length)

When I have [object Object],[object Object] with resultDateTransaction
Guess Iā€™m not using the hook the right wayā€¦

HI @nadtn,

It looks like you are not even using Moralis hooks anyway.

Please check out the hooks section to see how to use them. Hooks start with the key word ā€œuseā€.

If you have a promise, you could still get its result using something like

resultDateTransaction.then(
    function(value) {console.log(value);},
    function(error) {console.log(error);}
  );

When in react, sometimes you could use console.log(JSON.stringify(object_)) so that you can see what is there instead of [object Object]

Thanks guys, Moralis hooks are so useful and itā€™s easier when can check the value of [object Object].
Hope this is correct, I just canā€™t see the content in tbody but thead and everything else is there.


I only have Transactions.jsx now

import pageflip from "../data/pageflip.mp3";

import { Typography } from "@material-ui/core";

import { Moralis } from "moralis";

import { useMoralisQuery } from "react-moralis";


function millisecondsToTime (ms) {
    let minutes = Math.floor(ms / (1000 * 60));
    let hours = Math.floor(ms / (1000 * 60 * 60));
    let days = Math.floor(ms / (1000 * 60 * 60 * 24));
    
    if (days < 1) {
        if (hours < 1) {
            if (minutes < 1) {
                return `less than a minute ago`
            } else return `${minutes} minutes(s) ago`
        } else return `${hours} hours(s) ago`
    } else return `${days} days(s) ago`
  }

  const pageflipAudio = new Audio(pageflip);
  const playSound = audioFile => {
    audioFile.play();
}


export default function Transactions ({date}) {

    playSound(pageflipAudio);

        // set lessThan date
        let nextDate = new Date(date);
        nextDate.setDate(nextDate.getDate()+1);
              
        const { data, error, isLoading } = useMoralisQuery("EthTransactions", query =>
        query
          .greaterThan("block_timestamp", date)
          .lessThan("block_timestamp", nextDate),
          [date],
      );
      
    //console.log("Transactions json: " + JSON.stringify(data, null, 2))
    
    if (!error & data.length > 0) {

    return (
      <table border = "1" bordercolor = "blue">
      <caption>{data.length} transaction(s) {date.toLocaleDateString()}</caption>
      <thead>
      <tr>
      <th scope="col">Transaction</th>
      <th scope="col">Block Number</th>
      <th scope="col">Age</th>
      <th scope="col">Type</th>
      <th scope="col">Fee</th>
      <th scope="col">Value</th>
      <th scope="col">Notes</th>
          </tr>
      </thead>
      <tbody>
      {data.forEach((t) => {
          console.log("hash" + t.attributes.hash)
          return(
    <tr>
        <td><a href='https://etherscan.io/tx/${t.attributes.hash}' target="_blank" rel="noopener noreferrer">{t.attributes.hash}</a></td>
        <td><a href='https://etherscan.io/block/${t.attributes.block_number}' target="_blank" rel="noopener noreferrer">{t.attributes.block_number}</a></td>
        <td>{millisecondsToTime(Date.parse(new Date()) - Date.parse(t.attributes.block_timestamp))}</td>
        <td>{t.attributes.from_address == Moralis.User.current().get('ethAddress') ? 'Outgoing' : 'Incoming'}</td>
        <td>{((t.attributes.gas * t.attributes.gas_price) / 1e18).toFixed(5)} ETH</td>
        <td>{(t.attributes.value / 1e18).toFixed(5)} ETH</td>
        <td><input type="text" id="name" name="name"></input><button>Save</button></td>
    </tr>
      ); })}
      </tbody>
      </table>
    );

}
else {
    return (<Typography>No transactions</Typography>);
}
}