-1

I have a mapping and in each mapping i want to get data in the file storage IPFS such as the name. Then I want to return the name on the interface. However, I get a "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." Can someone please help me? been trying to solve this for hours. Can't seem to understand why because I know that hName should be a string.

{this.props.hawkers.map((hawker, key) => {
          const hawkerDetails = axios
            .get("https://ipfs.infura.io/ipfs/" + hawker.profileHash)
            .then(function (response) {
              console.log("this is the data: ", response.data);
              return response.data;
            })
            .catch(function (error) {
              console.log(error);
            });

          const hName = hawkerDetails.then((details) => {
            return hName;
          });
 return (
            <>
              <h4 style={{ display: "flex", marginTop: 20 }}>
                <Link
                  to={`/hawkerInfo/${hawker.owner}`}
                  // state={{ chosenHawkerPk: hawker.owner }}
                  state={{ chosenHawkerPk: hawker }}
                >
                  {hName}
                </Link>
              </h4>
mathsmad
  • 55
  • 6
  • what do you see if you console.log inside this function? const hName = hawkerDetails.then((details) => { console.log(details) }); I am wondering if the name could be on details.hName or something like that – Dan Aug 30 '21 at 17:05

1 Answers1

1

There are several things going on.

  1. You're not using React state to manage your data.

  2. You're passing in detailsas an argument to your then method, and then not using it so hName is meaningless. It should probably be details.hName.

  3. Ideally you want to create an array of promises and then process the data with Promise.all. In my example I've used async/await.

  4. Once you've set your state you then need to map over your data in your return to create the HTML.

// Initialise state
const [ hawkers, setHawkers ] = useState([]);

// Async function called by the `useEffect` method
async function getData() {

  // Create a list of Axios promises
  const promises = this.props.hawkers.map(hawker => {
    const url = `https://ipfs.infura.io/ipfs/${hawker.profileHash}`;
    return axios.get(url);
  });

  // Wait for all the data to return
  const responses = await Promise.all(promises);

  // Use `map` to return a new array of each response's data
  const hawkers = data.map(response => response.data);

  // Set the state with that array
  setNames(hawkers);
}

// useEffect runs once if you pass in an empty
// array dependency
useEffect(() {
  getData();
}, []);

if (!hawkers.length) return <div>Loading</div>;

// Now just `map` over the data that you put in state
return (
  <>
    {hawkers.map(hawker => {
      <h4>
        <Link to={`/hawkerInfo/${hawker.details.owner}`}>
          {hawker.details.name}
        </Link>
      </h4>
    })};
  </>
)
Andy
  • 61,948
  • 13
  • 68
  • 95
  • Hii thank u for ur answer. But this only works for functionality component right? Because I am using a class component. Do u know how I can do it on a class component instead? – mathsmad Aug 31 '21 at 02:59
  • 1
    Instead of `useEffect` use `componentDidMount`, and set state as `this.state = { hawkers: [] };` in the constructor, and then use `this.setState({ hawkers })` at the end of the function. You can then iterate over `this.state.hawkers` in the render. – Andy Aug 31 '21 at 03:31