3

I tried following this tutorial to get a feel of how dynamic routing would work. Now instead of using static data, I want to pull in blog posts using WordPress' API to generate unique links for each post. I'm able to generate the link, but none of the data is generating on the new page. What am I doing wrong here?

Articles.js (serves as the preview page to grab all the blog posts, works as expected)

import React, { Component } from 'react';
import { Link, Route } from 'react-router-dom';
import Article from './Article';

const newsURL = "http://myprivateblogapi.com/wp-json/wp/v2/posts?_embed";

export default class Articles extends Component {   
 constructor(props) {
    super(props);
    this.state = {
      newsData: [],
      requestFailed: false
    }   }

  componentDidMount() {
    fetch(newsURL)
      .then(response => {
        if(!response.ok) {
          throw Error("Network request failed.");
        }
        return response
      })
      .then(d => d.json())
      .then(d => {
        this.setState({
          newsData: d
        })
      }, () => {
        this.setState({
          requestFailed: true
        })
      })   }

  render() {

    let articles = this.state.newsData.map((article, index) => {
      if(this.state.requestFailed) return <p>Failed!</p>
      if(!this.state.newsData) return <p>Loading...</p> 
      return(
        <div key={index} className="article-container">
          <div className="article-preview">
          <span className="article-date">{article.date}</span>
          <h5>{article.title.rendered}</h5>
          <div dangerouslySetInnerHTML={{ __html: article.excerpt.rendered }} />

          <Link to={`/news/${article.slug}`}>Read More...</Link>

          </div>
          <Route path={`/news/:articleSlug`}
          render={ (props) => <Article data={articles} {...props} />} />
        </div>

      )
    });

    return (
      <div>
        <h3>All Articles from Blog</h3>
        {articles}
      </div>
    )   } }

Article.js (to render up each individual article)

import React from 'react';

const Article = ({match, data}) => {
  let article = data.find(a => a.slug == match.params.articleSlug);
  let articleData;

  if(article)
    articleData = <div>
      <h3> {article.title.rendered}</h3>
      { console.log(`${article.title.rendered}`) }
      <p>{article.content.rendered}</p>
      { console.log(`${article.content.rendered}`) }
      <hr />
    </div>
  else 
    articleData = <h2> Sorry. That article doesn't exist. </h2>;

    return (
      <div>
        <div>
          {articleData}
        </div>
      </div>
    )
}

export default Article;

1 Answer 1

2

I think issue is here:

render={ (props) => <Article data={articles} {...props} />} />

And in articles you are storing the result of map, so it will not have the data that you are expecting:

let articles = this.state.newsData.map(....)

Solution:

1- If you want to pass the full array then write it like this (not a good idea):

render={ props => <Article data={this.state.newsData} {...props} />} />

2- Pass the single object and looping will be not required inside Article component:

render={ props => <Article data={article} {...props} />} />

And Article component:

const Article = ({match, data}) => {
  let articleData;

  if(data)
    articleData = <div>
      <h3> {article.title.rendered}</h3>
      <p>{article.content.rendered}</p>
      <hr />
    </div>

  else 
    articleData = <h2> Sorry. That article doesn't exist. </h2>;

    return (
      <div>
        <div>
          {articleData}
        </div>
      </div>
    )
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you! That worked for a nested route. I had to rework the link and route to ${this.props.match.url}/${article.slug} and ${this.props.match.url}/:articleSlug, although i'm still trying to get it to pass the data on to its own page.
although i'm still trying to get it to pass the data on to its own page. didn't get this part? are you trying to pass full array to Article component?
nope, I've updated my code to pass the single article object so as not to loop again in the Article component. But the articles are all rendering on the Articles component, underneath the excerpts. I think it's because the route has to be nested. When I change the link back to /news/${article.slug} and the route back to /news/:articleSlug, nothing is rendered.
what was the issue when using ${this.props.match.url}/${article.slug} ??
I'm starting to see the problem, it's a problem with the <Switch> in the App component, I hadn't declared the route there.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.