javascriptreactjsspectacle

ReactJS: Dynamically add tags and content to react-dom and reload it


I am kind of new to reactJS and I am building a react app presentation with the help of spectacle. The content and amount of slides for the presentation are not known beforehand. Therefore, the basic idea is that at the beginning the app fetches data from a server. This data contains the content of the different slides. As there can be different types of slides, a template is stated as well. (There are 3 type of templates already defined in the app).

So what I am doing right now is: I am fetching the data and iterate over them. I check for the type of template a create a Slide Element for each of them. I then append the Slide Elements to the Deck. However, whenever I try to get the Deck it seems to be null and I cannot append anything to it. The next step would be to reload the whole react-dom with the new Deck-Content.

Additionally, I think that this is definitely not the way of doing it but I don't know how to do it better. So my question is: am I doing it right? Is there a better way? What do I do wrong?

Here is my Component:

import React from 'react';
import { Deck, Slide } from 'spectacle';
// import createTheme from 'spectacle/lib/themes/default';
import Template1 from '../Templates/template#1/template1';
import Template2 from '../Templates/template#2/template2';
import Template3 from '../Templates/template#3/template3';
import ReactDOM from 'react-dom'

export default class FullDeck extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            title: null,
            text: null
        }
        const defaultBackground = 'https://blog.visme.co/wp-content/uploads/2017/07/50-Beautiful-and-Minimalist-Presentation-Backgrounds-08.jpg';
    }

   componentDidMount() {

    fetch(' http://localhost:3030/getSlides')
      .then(results => {
        return results.json()
      }).then(data => this.processResults(JSON.parse(data)));

    }

    processResults(data) {
        const slideDeck = document.getElementById('slideDeck');
        console.log(slideDeck)
        data.forEach(slide => {
            let element;

            if(slide.type === 'template1') {
                element = (
                    <Slide bgImage={slide.backgroundImg || this.defaultBackground}>
                        <Template1 title={slide.title} text={slide.text}></Template1>
                    </Slide>
                )
                slideDeck.append(element);
            } else if(slide.type === 'template2') {
                element = (
                    <Slide bgImage={slide.backgroundImg || this.defaultBackground}>
                        <Template2 title={slide.title} text={slide.text} slideImg={slide.img}></Template2>
                    </Slide>
                )
                slideDeck.append(element);
            } else if(slide.type === 'template3') {
                element = (
                    <Slide bgImage={slide.backgroundImg || this.defaultBackground}>
                        <Template3 title={slide.title} slideImg={slide.img}></Template3>
                    </Slide>
                )
                slideDeck.append(element);
            }
        })
        ReactDOM.render(slideDeck, document.getElementById('root'));
    }

    render() {
    const defaulText = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. ";
    const slideImg = "https://cdn.worldvectorlogo.com/logos/some.svg";
        const graph = "https://www.mathsisfun.com/data/images/bar-graph-fruit.svg";

        return (
            <div id='root'>
              <Deck  id='slideDeck'>
              </Deck>
            </div>

        )
    }
}

Solution

  • Instead of calling ReactDOM.render inside processResults, you could call it outside of the component from the start, and e.g. keep an empty slides array in your state until your network request is complete. This way you can put the slides data in your component state and derive the JSX from that data in the render method.

    Example

    class FullDeck extends React.Component {
      state = {
        title: null,
        text: null,
        slides: []
      };
    
      componentDidMount() {
        fetch(" http://localhost:3030/getSlides")
          .then(response => response.json())
          .then(data => this.setState({ slides: data }));
      }
    
      render() {
        const { slides } = this.state;
    
        if (slides.length === 0) {
          return null;
        }
        return (
          <Deck>
            {slides.map((slide, index) => {
              if (slide.type === "template1") {
                return (
                  <Slide
                    key={index}
                    bgImage={slide.backgroundImg || this.defaultBackground}
                  >
                    <Template1 title={slide.title} text={slide.text} />
                  </Slide>
                );
              } else if (slide.type === "template2") {
                return (
                  <Slide
                    key={index}
                    bgImage={slide.backgroundImg || this.defaultBackground}
                  >
                    <Template2
                      title={slide.title}
                      text={slide.text}
                      slideImg={slide.img}
                    />
                  </Slide>
                );
              } else if (slide.type === "template3") {
                return (
                  <Slide
                    key={index}
                    bgImage={slide.backgroundImg || this.defaultBackground}
                  >
                    <Template3 title={slide.title} slideImg={slide.img} />
                  </Slide>
                );
              }
            })}
          </Deck>
        );
      }
    }
    
    ReactDom.render(<FullDeck />, document.getElementById("root"));