1

Suppose I had the following two files:

example.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta charset="utf-8" />
    <title>Example</title>
    <script type="text/javascript" src="BodyPrinter.js"></script>
</head>

<body id="body" onload="init()">
    <button onclick="bodyPrinter.printBody()">Print body</button>
    <script>
        function init() {
            bodyPrinter = new BodyPrinter();
        }
    </script>
</body>
</html>

BodyPrinter.js

function BodyPrinter() {
    this.body = document.getElementById('body');
};

BodyPrinter.prototype.printBody = function () {
    console.log(this.body);
}

This prints the of the HTML when the button is clicked. This works because the HTML is first loaded, with all of its elements, and then the init() creates the BodyPrinter that will access the HTML element and print it.

Right now I'm converting to React, and attempting to change as little as possible (aside from adding an export export default BodyPrinter; in BodyPrinter.js);

convert.jsx

import * as React from 'react';
import BodyPrinter from './BodyPrinter';

export default class Entry extends React.Component {
    constructor(props) {
        super(props);
        this.bodyPrinter = new BodyPrinter();
    }


    render() {
        return (
            <div>
                <title>Example</title>
                <button onClick={() => this.bodyPrinter.printBody()}>Print body</button>
            </div>

        )
    }
}

For my purposes, I need to access BodyPrinter in the render() method, therefore I need to create it in the constructor. The issue is that the constructor is called before the HTML is created, so the BodyPrinter will just print null.

How can I resolve this/get the HTML to load first without modifying BodyPrinter.js and still being able to access it in the render()?

Solution:

I've figured a solution. Just place the classes you want to instantiate in componentDidMount() instead of the constructor. That way you can still access them in the render().

1
  • 1
    have you tried componentDidMount. there used to be componentWillMount, which is now UNSAFE_componentWillMount() in the current version of React. You should probably avoid UNSAFE_componentWillMount(), but for testing purpose you can try it. Commented Jan 9, 2019 at 18:27

2 Answers 2

1

Something like this?

import * as React from 'react';
import BodyPrinter from './BodyPrinter';

export default class Entry extends React.Component {
    constructor(props) {
        super(props);        
    }

    print() {
        var bodyPrinter = new BodyPrinter();
        bodyPrinter.printBody();
    }


    render() {
        return (
            <div>
                <title>Example</title>
                <button onClick={() => this.print}>Print body</button>
            </div>

        )
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

First of all, if we consider performance. we shouldn't create a function in render method, because after every reRender its will create a new function, and second is we should bind function or use arrow function to change the this:

import * as React from 'react';
import BodyPrinter from './BodyPrinter';

export default class Entry extends React.Component {
    constructor(props) {
        super(props);    
        this.bodyPrinter = new BodyPrinter();    
    }

    print = () => {
        this.bodyPrinter.printBody();
    }


    render() {
        return (
            <div>
                <title>Example</title>
                <button onClick={this.print} type="button">Print body</button>
            </div>

        )
    }
}

Comments

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.