React where in the component to add a simple math function

Viewed 8863

I have a simple react component to which I want to add a simple math function named doMath that uses property values.

class MyClass extends Component {
    constructor( props ) {
        super( ...arguments );
    }

    render() {
        const { attributes } = this.props; /* attributes passed from parent component */
        const { width, height } = attributes;

        return (
           /* render something using the width and height values */
        )
    }
}

I can add the doMath function in the following ways...

Inside the class:

class MyClass extends Component {
    constructor( props ) {
        super( ...arguments );
    }

    doMath() {
       const { width, height } = this.props.attributes;
       const result = 100 / (width / height);
       return result;
    }

    render() {
        const { attributes } = this.props; /* attributes passed from parent component */
        const { width, height } = attributes;

        return (
           doMath();
        )
    }
}

Outside the class as a const:

const doMath = (width, height) {
  const result = 100 / (width / height);
  return result;
}

class MyClass extends Component {
    constructor( props ) {
        super( ...arguments );
    }

    render() {
        const { attributes } = this.props; /* attributes passed from parent component */
        const { width, height } = attributes;

        return (
           doMath(width, height);
        )
    }
}

Inside render as a const:

class MyClass extends Component {
    constructor( props ) {
        super( ...arguments );
    }

    render() {
        const { attributes } = this.props; /* attributes passed from parent component */
        const { width, height } = attributes;

        const doMath = (width, height) {
           const result = 100 / (width / height);
           return result;
        }

        return (
           doMath(width, height);
        )
    }
}

Seems like I can also add it to componentDidMount or componentDidUpdate

From what I understood it is bad practice to add it in render() but it seems to work everywhere. What is the best practice in this situation?

3 Answers

The third method is certainly not ok. Adding the function inside the render method will create a new doMath function every time your component re-renders, and that's not a performant way of doing things.

If you know for sure you're going to use the doMath function only for this particular component, I would suggest defining it in the component's module without exporting it. So I would opt for the second way.

If this function only depends on width and height, then it's good to have it outside the component's class. Otherwise, if you feel like it might depend on more of the state, you could put it inside the class so you are not forced to pass the component's state around.

Conclusion: depending of how much data you are going to pass to the doMath function you can either create it inside the class or outside of it; but never in the render method.


EDIT: Something I forgot to mention is using a static method. Basically if you're not setting the method static, it will be created for every instance of your component and will be able to use other class members:

(A) If the method's not static:

class MyComponent extends React.Component {
  /* private */ doMath() {
    // You have access to this particular instance and its state
    const {width, height} = this.state; 
  }
}

(B) If the method is static:

class MyComponent extends React.Component {
  /* private */ static doMath(width, height) {
    // do something with them
    // no access to state or the component's instance
  }

  render() {
    const {width, height} = this.state;

    const result = MyComponent.doMath(width, height);

    // render something
  }
}

(C) And for completeness, let's also define the function outside the class:

function doMath(width, height) {
  // do magic
  return result;
}

class MyComponent extends React.Component {
  render() {
    const {width, height} = this.state;
    const result = doMath(width, height);

    // render something
    // use result
  }
}

// emphasize export
module.exports = MyComponent;

Comparison

When using something like TypeScript, methods (B) and (C) are basically giving the same result: you can isolate functionality by specifing the static method private. However, when using JavaScript, I prefer (C) because if I do

const MyComponent = require('/path/to/MyComponent');
MyComponent.doMath(); // undefined

I cannot use the doMath function because I shouldn't. With these two methods, you need to pass the required data to the function/method as parameters (i.e. you don't have access to the component instance's internal state).

Now for (A), the method will be created for every instance of the component (maybe something to consider if you have many of them). You will have access to this (so to the component's internal state) and you don't have to pass anything as parameter, which may be convenient if you are unsure how much data the method needs.

I hope you'll be able to draw a conclusion from this explanation.

The best way of these 3 is inside the class, since then other components can reuse that component with the math function. If you do that outside of the component this function is no longer tied to the component. However, in the future it is very likely that Class components will be obsolete and will no longer receive updates since Hooks are the new thing that make all the components have state. If function was stateless before it will be stateful in the hooks version and you should read about it it is a great thing!

Just put it inside the class and call it by {this.doMath()} in the render method

class MyClass extends Component {
    constructor( props ) {
        super( ...arguments );
    }

    doMath() {
       const { width, height } = this.props.attributes;
       const result = 100 / (width / height);
       return result;
    }

    render() {
        const { attributes } = this.props; /* attributes passed from parent component */
        const { width, height } = attributes;

        return (
           {this.doMath()}
        )
    }
}
Related