0

I am currently building an RSS News Feed in SPFx using React as a framework and using an XML link https://feeds.expressen.se/nyheter/ (Swedish news if curious).

I can display all items, in this case title and author, in the console but in the webpart it only displays one item (the latest one).

I want to show all items in the webpart as well, that is a main purpose for an RSS Feed.

Here is how the webpart and console look like now (in Chrome): enter image description here

Here is the code: RssApp.tsx: (I am using a for loop to iterate over all items but it doesn't seem to work on the SPFx)

import * as React from 'react';
import styles from '../RssApp.module.scss';
import { IRssAppProps } from './IRssAppProps';
import {IRssAppState} from './IRssAppState'

export default class RssApp extends React.Component<IRssAppProps, IRssAppState> {
  constructor(props: IRssAppProps){
    super(props);
    this.state = {
        title: '',
        description: '',
        author: ''
    }
  }

  showSomeXML(){

      var xhttp = new XMLHttpRequest();

      xhttp.onreadystatechange = () => {
        if(xhttp.readyState == 4 && xhttp.status == 200){

          /**For loop iterating over items (i.e. all news article items) */
          for(let i = 0; i < xhttp.responseXML.getElementsByTagName('item').length; i++){

            /***Showing in the console */
             console.log("Title: " + xhttp.responseXML.getElementsByTagName('item')[i].children[3].innerHTML);
             console.log("Author: " + xhttp.responseXML.getElementsByTagName('item')[i].children[2].innerHTML);   

             /**Set State to innerHTML from the xml file */
                this.setState(
                {  
                  title: xhttp.responseXML.getElementsByTagName('item')[i].children[3].innerHTML,
                  author: xhttp.responseXML.getElementsByTagName('item')[i].children[2].innerHTML
                })

          }
          console.log("News items: " + xhttp.responseXML.getElementsByTagName('item').length);
          console.log(xhttp.responseXML.getElementsByTagName('item')[1].children);
        }
      };
      xhttp.open("GET", 'https://feeds.expressen.se/nyheter/', true);
      xhttp.send();
  }

  componentDidMount(){
    {this.showSomeXML()}
  }

  public render(): React.ReactElement<IRssAppProps> {
    return (

              <div className={ styles.title }>{this.state.title}
                  <div>{this.state.description}</div>
                  <div>{this.state.author}</div>
              </div>
    );
  }
}

Here are the states defined IRssAppState.ts:

export interface IRssAppState{ 
    title: string;
    description: string;
    author: string;
}

Very strange since I do have a for loop iterating over all items and I do setState within the for loop.

Would appreciate all help I can get with this issue. Thanks in advance.

1 Answer 1

0

Basically the problem is that your state is can and will show only one last item. You need to change it to be able to save an array in there:

export interface IRssItem{
    title: string;
    description: string;
    author: string;
}

export interface IRssAppState{ 
    items: IRssItem[];
}

Then:

showSomeXML(){

  var xhttp = new XMLHttpRequest();

  xhttp.onreadystatechange = () => {
    if(xhttp.readyState == 4 && xhttp.status == 200){
      let feedElementsArray:IRssItem[] = [];
      /**For loop iterating over items (i.e. all news article items) */
      for(let i = 0; i < xhttp.responseXML.getElementsByTagName('item').length; i++){

        /***Showing in the console */
         console.log("Title: " + xhttp.responseXML.getElementsByTagName('item')[i].children[3].innerHTML);
         console.log("Author: " + xhttp.responseXML.getElementsByTagName('item')[i].children[2].innerHTML);   
         feedElementsArray.push({  
              title: xhttp.responseXML.getElementsByTagName('item')[i].children[3].innerHTML,
              author: xhttp.responseXML.getElementsByTagName('item')[i].children[2].innerHTML
            });


      }
      this.setState({
        items:feedElementsArray
      });
      console.log("News items: " + xhttp.responseXML.getElementsByTagName('item').length);
      console.log(xhttp.responseXML.getElementsByTagName('item')[1].children);
    }
  };
  xhttp.open("GET", 'https://feeds.expressen.se/nyheter/', true);
  xhttp.send();

}

And finally the render method where you render from the array:

public render(): React.ReactElement<IRssAppProps> {
      const singleElement = (element:IRssItem)=>{
          return (
             <div className={ styles.title }>{element.title}
                <div>{element.description}</div>
                <div>{element.author}</div>
             </div>
          );
      };
      return (
          <div className='elementsContainer'>
              {this.state.items.map(singleElement)}
          </div>
      );

}

Hope it helps:)

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.