[Solved] Is there a way to display a Solidity array of structs in React?

Kamil Asks: Is there a way to display a Solidity array of structs in React?
I am trying to display the contents of a Solidity array of structs in a React front-end.

This is my Solidity smart contract. I’ve created a function which returns the length of the array in question.

Code:
pragma solidity ^0.8.0;

contract Project {

    struct Person {
        string name;
        string description;
    }
    
    Person[] public people;

    function getPersonCount() public view returns (uint) {
        return people.length;
    }

}

Here is my front-end React code:

Code:
import React from "react";
import Web3 from './web3';
import { ABI } from './ABI';
import { contractAddr } from './Address';

const web3 = new Web3(Web3.givenProvider);
const ContractInstance = new web3.eth.Contract(ABI, contractAddr);

const NewPerson = () => {

    let personCount = 0;

    personCount = ContractInstance.methods.getPersonCount().call();

    return (
        personCount
    );
};

export default NewPerson;

When I run that front-end code, I get this error message:

Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.

Reading answers to questions on here, I thought the problem might be that I need to call my Solidity function asynchronously so that I can return the output of the function rather than a promise. I tried re-writing my React code like so:

Code:
import React from "react";
import Web3 from './web3';
import { ABI } from './ABI';
import { contractAddr } from './Address';

const web3 = new Web3(Web3.givenProvider);
const ContractInstance = new web3.eth.Contract(ABI, contractAddr);

const NewPerson = () => {

    let personCount = 0;

    async function handlePerson() {
        personCount = await ContractInstance.methods.getPersonCount().call();
    }

    handlePerson();

    return (
        personCount
    );
};

export default NewPerson;

This did not trigger an error, but instead returned 0 (suggesting that the handlePerson function did not even run).

I then tried another approach:

Code:
import React from "react";
import Web3 from './web3';
import { ABI } from './ABI';
import { contractAddr } from './Address';

const web3 = new Web3(Web3.givenProvider);
const ContractInstance = new web3.eth.Contract(ABI, contractAddr);

const NewPerson = () => {


    let personCount = 0;

    async function handlePerson() {
        personCount = await ContractInstance.methods.getPersonCount().call();
        
        return (
            personCount
        );
    }
    return (
        handlePerson()
    );

};

export default NewPerson;

This gave me the same error message I got the first time around:

Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.

I’d be grateful if anyone has any advice to offer, or if anyone has experienced something similar. My goal is to then iterate through the array to display all of its elements, but so far I don’t even seem to be able to display the number of elements in it. It’s particularly strange since I’m successfully able to call other functions from my smart contract via the React front-end. Many thanks in advance!

Update:​

Many thanks to MrFrenzoid for the help. I’ve re-written my front-end code so that I am now able to query individual elements of the Solidity array:

Code:
import React from "react";
import Web3 from './web3';
import { ABI } from './ABI';
import { contractAddr } from './Address';

const web3 = new Web3(Web3.givenProvider);
const ContractInstance = new web3.eth.Contract(ABI, contractAddr);

const NewPerson = () => {
    
    // Using hard-coded personCount for testing purposes
    let personCount = 70;
    let people = [];

    async function handlePeople() {
        for (let i=0; i<personCount; i++) {
            const person = await ContractInstance.methods.people(i).call();
            people.push(person);
        }
        console.log(people);
    }

    handlePeople();

    return (
        null
    );

};

export default NewPerson;

This returns the contents of the array in the console, as expected. The issue I’m still having is querying the length of the Solidity array, so that I can use that to compute personCount (rather than using a hard-coded value as I do above).

Code:
import React from "react";
import Web3 from './web3';
import { ABI } from './ABI';
import { contractAddr } from './Address';

const web3 = new Web3(Web3.givenProvider);
const ContractInstance = new web3.eth.Contract(ABI, contractAddr);

const NewPerson = () => {

    let people = [];

    async function handlePersonCount() {
        const personCount = await ContractInstance.methods.getPersonCount().call();
        console.log(personCount);
    }

    async function handlePeople() {
        for (let i=0; i<personCount; i++) {
            const person = await ContractInstance.methods.people(i).call();
            people.push(person);
        }
        console.log(people);
    }

    handlePersonCount();
    handlePeople();

    return (
        null
    );

};

export default NewPerson;

When I run handlePersonCount(), I get this error message:
error message

The reason I’m taking this approach at all is because I’m seemingly unable to query the entire Solidity array at once, and instead need to query one element at a time.

Ten-tools.com may not be responsible for the answers or solutions given to any question asked by the users. All Answers or responses are user generated answers and we do not have proof of its validity or correctness. Please vote for the answer that helped you in order to help others find out which is the most helpful answer. Questions labeled as solved may be solved or may not be solved depending on the type of question and the date posted for some posts may be scheduled to be deleted periodically. Do not hesitate to share your response here to help other visitors like you. Thank you, Ten-tools.