tim_d
tim_d

Reputation: 133

React component continuously updating

I am trying to convert markdown files to html. I am able to do so with a package called showdown, but the goToPage component continuously runs as seen by hundreds of console logs continuously flowing.

The below code allows the user to type in a filename in the url and an express server returns a markdown file. React then converts it to html and displays that html. I'm aware that the return div is empty after the first run and depends on the state being updated when the data has been fetched, but I don't know how to break the loop after that.

class App extends Component {
  state = { myFile: '' }

  constructor(props) {
    super(props);

    this.goToPage = this.goToPage.bind(this);
  }

  goToPage = ({ match }) => {
    fetch('/' + match.params.filename)
      .then((res) => res.text())
      .then((text) => {
        console.log(text);
        var fileContents = text;

        var showdown = require('showdown'),
          converter = new showdown.Converter(),
          markdown = fileContents,
          html = converter.makeHtml(markdown);

        console.log(html);
        this.setState({ myFile: html });
      })
      .catch(err => {
        console.log(err);
      });

    return (
      <div dangerouslySetInnerHTML={{ __html: this.state.myFile }} />
    )
  }

  render() {
    return (
      <Router>

        <Route path="/:filename" component={this.goToPage} />

      </Router >
    );
  }
}

export default App;

I'm quite new to React, so I don't know if my goToPage should even be in the same class- still learning the basics. I'd love to know if I'm doing something stupid.

Upvotes: 2

Views: 880

Answers (1)

Agney
Agney

Reputation: 19194

<Route path="/:filename" component={this.goToPage} />

This line asks the router to render whatever is in the this.goToPage as the component on the said route. But if you check the goToPage function, it uses this.setState that rerenders the browser. The route tries to render the goToPage function again and the cycle repeats.

Instead, what you need to do is to render another component in route /:filename and make sure that fetch runs only once.

<Route path="/:filename" component={MarkdownConverter} />

Now, inside MarkdownConverter component:

class MarkdownConverter extends Component {
  this.state = {
    myFile: ""
  }
  componentDidMount() {
    // All the logic for fetch and convert goes here.
  }
  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: this.state.myFile }} />
    );
  }
}

Upvotes: 1

Related Questions