0

i have a gallery of images in the main view, and I want to be able to click each image to open a new child view showing details (eg text such as image title). my hardcoded version -- where images and text are stored in frontend -- works. but when I store the data in a MySQL database, i'm running into a problem -- eg unable to drill down into the details when an image is clicked.

the data seems to be fetched properly from backend to frontend because the images of the gallery are showing up. in my mind, the difference (between the hardcoded version and database-connected version) lies largely in react router v4's setup, perhaps a syntax issue that is preventing the paths from matching or preventing data from being passed to the child view:

ReactDOM.render(
..
<Route path="/articles/:PostId" render={(props) => (<Post articles={this.state.blurbs} {...props} />)} />

when it comes to errors, I get different messages depending on the browser: one says "TypeError: Unable to get property 'blurbs' of undefined or null reference;" other says "TypeError: this.state is undefined"

for brevity, my array state is initialized as such:

class App extends React.Component
..
this.state = {
  blurbs: []
}

the value of the array state is updated as such:

componentDidMount()
..
let self = this;
..
return response.json();
...
.then(function(data) {
  self.setState({blurbs: data});
})

in child component, data is rendered based on unique id in database as such:

render
..
return
..
{this.props.articles[this.props.match.params.PostId].Title}

so going back, what's wrong with the syntax in react router assuming everything above makes sense? tia

femtowatts
  • 63
  • 1
  • 7

2 Answers2

0

The issue is that the data coming from the API (eg: MySQL) is likely an array. However, you're treating it like a js object.

In your child component's render function, you need to use the findIndex method to find which element of the array that contains the value of your PostId URL parameter (docs). This is assume your table has an id element that is your primary key.

render() {
  const idx = this.props.articles.findIndex(x => x.id === this.props.match.params.PostId);

  const article = idx > -1 ? this.props.articles[idx] : {};

  return (
    ...
    {article.Title}
    ...
);
technogeek1995
  • 3,185
  • 2
  • 31
  • 52
  • 1
    thanks for your time. i gave several goes to your suggestion -- tried it verbatim, tweaked things around to no avail. could just be me though. i'll revisit this approach in addition to seeing if there's a way to convert array to js object. if all else fails, i might just fall back on the hardcoded version (which is already working at least) for time being. – femtowatts Aug 23 '19 at 03:42
  • Yeah my guess would be the reason it didn't work was that `Title` would be undefined if `.findIndex` was `-1` (like while the page is loading). I updated my answer to handle this better. – technogeek1995 Aug 23 '19 at 13:41
  • thanks for taking a second stab at my problem. at this rate, i'll work on this offline to ensure i have the basics right. your notes will be helpful as i improve my understanding in react implementation. if i find the solution, i'll post it here to share. – femtowatts Aug 31 '19 at 02:35
0

to bring "closure" to this thread, i'm sharing what worked for me. instead of passing all props from parent to child via react router, i ended up passing some props from parent to child through the image link.

the issue -- that props was not completely getting from parent to child -- was not immediately clear to me. i narrowed down my issue by tinkering around (eg substituting parts of the project with hardcode to identify the problematic parts of the code).

i found a thread where someone else was experiencing similar blockage in data transfer via react router. after several roadblocks, here are the changes that got me moving forward again.

in parent component, state reference was removed from react router to look as such:

ReactDOM.render(
..
<Route path="/articles/:PostId" render={(props) => (<Post {...props}/>)} />

in parent component, state reference was added to image link to use Link as a data transfer medium as such:

render() {
return (
<div>
  {this.state.blurbs.map(image => (
    <Link key={image.PostId}
    to={{pathname: `/articles/${image.PostId}`,
    state: { blurbs: this.state.blurbs }
    }}>
    <img src={image.src}/>
    </Link>
    ))
    }
</div>

in child component, this.props.location.state.blurbs was added as replacement to make the data (originally fetched in parent) accessible to child as such:

render
..
return
..
{this.props.location.state.blurbs[this.props.match.params.PostId].Title}

here's the link to the other thread: How do i pass state through React_router?

femtowatts
  • 63
  • 1
  • 7