8

I just begun to learn React and JavaScript in general. After I read the documentation and tutorials, I took a look at example projects and try to sort out what I didn't get yet.

And then I saw that there are functions that are defined inside the render()functions, and some that are outside of the render() function.

E.g. for outside of render():

handleClick(e) {
    e.preventDefault();
    e.target.parentElement.classList.toggle('open');
  }

and inside render()...

const divider = (divider, key) => {
      const classes = classNames( 'divider', divider.class);
      return (<li key={key} className={ classes }></li>);
    };

Why do they look so different and why would you like to have some functions inside and some outside of render()?

EDIT:

Another example for a function outside of render():

hideMobile() {
    if (document.body.classList.contains('sidebar-mobile-show')) {
      document.body.classList.toggle('sidebar-mobile-show')
    }
  }

EDIT2: In another thread someone answered that, if the logic behind the function is heavy, it should be outside of render(). But why would you like to have function inside render() anyways?

yemerra
  • 1,352
  • 4
  • 19
  • 44
  • To my knowledge, everything inside `render()` is continuously looped. – ionizer Apr 02 '18 at 17:53
  • @ionizer Well I know that, but why would you like to have functions that are inside a continuously looped function? – yemerra Apr 02 '18 at 17:55
  • divider is called a lambda function or an anonymous function. sometimes, you want it to define and use function only once. In this case, I believe you can move `divider` to outside of render() function just fine since it doesn't refer to any outer scope variables. – digitake Apr 02 '18 at 17:59
  • Possible duplicate of [Function inside render and class in reactjs](https://stackoverflow.com/questions/42645297/function-inside-render-and-class-in-reactjs) – illiteratewriter Apr 02 '18 at 18:04
  • Sorry about that. As for me I do put things inside `render` when I want my HTML or variable to automatically update itself, with or without `state`. – ionizer Apr 02 '18 at 18:05
  • @digitake So what you are saying is that the reason for having functions outside or inside of render() is the scope? – yemerra Apr 02 '18 at 18:41
  • 1
    @Goldi yes, that would be major conceivable reason to me. – digitake Apr 02 '18 at 19:02
  • @digitake I think that would be the answer to my question. I should have seen that before. So if you look at my `hideMobile()` function: is this function doing anything that can only be done outside of the render() function or is better to be done outside? – yemerra Apr 02 '18 at 19:07
  • @Goldi, **in my opinion** function **declaration** is always better outside of `render()`, the matter is if you should **call** it inside the `render()`, my original answer seems not proper to your real question, I've updated, hope it's helped – Carr Apr 03 '18 at 06:26

3 Answers3

5

render() is called everytime the state change. So every function that is kept inside render function will be created as a new function each time the state change. Which means that divider will be created newly every time react re-renders.

handleClick is a normal object function.

Functions written inside render function are usually those dealing with rerendering of components.

illiteratewriter
  • 4,155
  • 1
  • 23
  • 44
3

From example on official site:

First, if we want to build a Clock in the beginning, this how we tried to make a component that is object-oriented, maintainable factor with a stateless function object.

function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

function tick() {
   ReactDOM.render(
     <Clock date={new Date()} />,
     document.getElementById('root')
   );
}

setInterval(tick, 1000);

quote from doc

to make the Clock component truly reusable and encapsulated. It will set up its own timer and update itself every second.

... Ideally we want to write this once and have the Clock update itself...

So here is the spirit of React, we want to convert this function object to a class, which could maintain itself, so now we involve render() in, more specifically we involve stateful component in:

Add a single empty method to it called render()
...
Clock is now defined as a class rather than a function.

Then we get:

class Clock extends React.Component {
    constructor(props) {
        super(props);
        this.state = {date: new Date()};
        this.clockCore = this.clockCore.bind(this);
    }

    componentDidMount() {
        this.timerID = setInterval(
          () => this.tick(),
           1000
        );
     }

     tick() {
         this.setState({
             date: new Date()
         });
     }

     clockCore() {
         return (<div>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
         </div>);
     }

     render() {
        return this.clockCore();
     }
}

As you known, render() be triggered again an again if the state of component need to be refreshed by setState().


Update

In my opinion, it's unnecessary to define the function in render(). I have made a little revisions to the original example above to show that.

From example you provided, the usage of divider may be like:

const divider = (divider, key) => {
  const classes = classNames( 'divider', divider.class);
  return (<li key={key} className={ classes }></li>);
};

return (<ul>{this.state.dividerList?
    this.state.dividerList.forEach(divider) : null}</ul>);

I think the reason of this is just for maintainability, someone may want all DOM creating code inside the render() for easy tracing when DOM structure returned is really complicated (and arrow function is lightweight), but as I said it's subjective, it really could be defined outside.

In this kind of case, I used to do below instead, and it seems what you provided is more elegant, but if you defined that function outside of render(), things become distractive to me.

let dividers = [];
if (this.state.dividerList) {
    this.state.dividerList.forEach((divider, key) => {
        let classes = classNames( 'divider', divider.class);
        dividers.push((<li key={key} className={ classes }></li>));
    });
}

return (<ul>{dividers}</ul>);

So another function you provided which aims at DOM manipulations feature is totally proper and well to be defined outside.

Carr
  • 2,691
  • 1
  • 19
  • 27
0

Besides that, handleClick is a function created and accessible for every Object/Component and divide is a locally scoped function, their functionality can be pretty much the same. However, divider will be created as new function on every render which might have later performance implications, while handleClick is created once for a defined component (Object).

Tomasz Mularczyk
  • 34,501
  • 19
  • 112
  • 166
  • Well, I knew the behaviour that you describe already, just I don't know why you want that to happen. Without knowing 'why', I would assume that putting functions inside the render() function is always bad since render will be called constantly and so the functions that are inside render() will be redefined constantly – yemerra Apr 02 '18 at 17:57
  • @Goldi `render will be called constantly` - no, why? only if you pass that function as a `prop` then children component will get always a new function - when in fact it doesn't changed. – Tomasz Mularczyk Apr 02 '18 at 18:11
  • Sorry, thats what I mean by constantly. I mean what you described. (what I actually meant was continuously) – yemerra Apr 02 '18 at 18:39