0

I'm trying to create a table with React that will receive JSON data eventually (via HTTP request). I am currently storing the data in the state of my first component, and then rendering the table in my second component.

I would like each row in my table to contain an image of an album cover, followed by text data about the track, artist, and album title. For this post, I will include one row of my data so that you may see how it is stored in state.

I am currently unable to render an image stored as a string in state. What could I changed about my getRowsData() function in order to make this work? Or maybe I need to change how I am calling my image string? Any help or advice would be greatly appreciated.

The state (with image string as a .jpeg file) is found here:

import React, { Component, useState, Fragment } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import AudioPlayer from './AudioPlayer';
import Table from './Table/TrackInfo';
import '../components/AudioPlayer.css';
import '../adrian_trinkhaus.jpeg';

export default class PostContent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      tracklist: this.props.tracklist,
      data: [
        {
'Album Art': '../adrian_trinkhaus.jpeg', 
'Artist': 'The Olivia Tremor Control', 
'Track Title': 'The Opera House', 
'Album Title': 'Music From The Unrealized Film Script: Dusk At Cubist Castle'},
    ] 
    }
  }

  render() {
    console.log(this.props.tracklist)
    return (
      <Fragment>
        {/*Audio Player and Related*/}
        <AudioPlayer />
        <Link id='home-link' to='/' activeClassName='active'>Homepage</Link>
        <div className="word-content">
          <h2 className="show-title">{this.props.showTitle}</h2>
          <div className="episode-post-content">{this.props.content}</div>
          <Table data={this.state.data} />
          <div className="bottom-link">
            <Link id='home-link' to='/' activeClassName='active'>Homepage</Link>
          </div>
        </div>
      </Fragment>
    )
  }
}

The table is created here:

import React, { Component } from 'react';
export default class Table extends React.Component {

  constructor(props) {
    super(props);
    this.getHeader = this.getHeader.bind(this);
    this.getRowsData = this.getRowsData.bind(this);
    this.getKeys = this.getKeys.bind(this);
  }

  getKeys = function () {
    return Object.keys(this.props.data[0]);
  }

  getHeader = function () {
    var keys = this.getKeys();
    return keys.map((key, index) => {
      return <th key={key}>{key.toUpperCase()}</th>
    })
  }

  getRowsData = function () {
    var items = this.props.data;
    var keys = this.getKeys();
    return items.map((row, index) => {
      return <tr key={index}><RenderRow key={index} data={row} keys={keys} /></tr>
    })
  }

  render() {
    return (
      <div>
        <table>
          <thead>
            <tr>{this.getHeader()}</tr>
          </thead>
          <tbody>
            {this.getRowsData()}
          </tbody>
        </table>
      </div>

    );
  }
}
const RenderRow = (props) => {
  return props.keys.map((key, index) => {
    return <td key={props.data[key]}>{props.data[key]}</td>
  })
}

Jon
  • 622
  • 8
  • 29

1 Answers1

1

You have to use HTML <image> element to display images so in your RenderRow function try to do this modification

const RenderRow = (props) => {
  return props.keys.map((key, index) => {
    return(
    <td key={props.data[key]}>
    <img src={props.data.Album Art} alt="Album Art" className="yourCustomStyle"/>
    <div>{props.data.Artist}</div>
     <div>{props.data.Track Title}</div>
    </td>
  )})
}

TIP:

In Table class instead of binding this to every function you can convert those functions to arrow functions which binds this automatically to a function. It will make your code shorter and cleaner. So to convert a function into arrow function all you have to do is this

functionName = (arguments) => {
  console.log("This is an arrow function")
}

Do this to all your functions and remove this binding in the constructor.

Hope it helps

Hadi Mir
  • 4,497
  • 2
  • 29
  • 31
  • Thanks - though I am still not able to get the image to render, only a broken image link with the alt text. I believe the image is Additionally, with the code below (see other comment), I am getting a table with one row, but the data is copied four times, so my data looks like: album_art | artist | track_title | album_title | (x4...) How do I modify the (key, index) arguments in your response to only generate one row with four table data entries, and do you know why the image is still not rendering? The path to the image is correct in the file structure. – Jon Apr 20 '20 at 14:36
  • ``` const RenderRow = (props) => { return props.keys.map((key, index) => { return ( Album Art {props.data.artist} {props.data.track_title} {props.data.album_title} ) }) } ``` – Jon Apr 20 '20 at 14:36
  • you are getting "only a broken image link with the alt text." because the< img /> tag is not able to locate the image. This happens because to use local images in react you have to import them first . Have a look at this https://stackoverflow.com/questions/39999367/how-do-i-reference-a-local-image-in-react/61316673#61316673 – Hadi Mir Apr 20 '20 at 15:53
  • Thank you - I can see the image now! The only issue now is that the data is copied four times in the row. I only have four columns, but the DOM is rendering four copies of the table data. Is this an issue with how the Render Row function? (below) – Jon Apr 20 '20 at 16:06
  • const RenderRow = (props) => { return props.keys.map((key, index) => { return ( Album Art {props.data.artist} {props.data.track_title} {props.data.album_title} ) }) } – Jon Apr 20 '20 at 16:09
  • The RenderRow function is being sent to getRowsData... maybe the issue is with how the data is presented here? getRowsData = () => { var items = this.props.data; var keys = this.getKeys(); return items.map((row, index) => { return }) } – Jon Apr 20 '20 at 16:11
  • Okay, I fixed it - I was rendering the data four times because I was using a map()function twice. Taking out the map in the RenderRow() function solved it for me. Thanks so much for your help with the image and with the table! – Jon Apr 20 '20 at 16:54