Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functions inside and outside render()

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?

like image 660
yemerra Avatar asked Apr 02 '18 17:04

yemerra


2 Answers

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.

like image 165
illiteratewriter Avatar answered Sep 19 '22 02:09

illiteratewriter


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.

like image 24
Carr Avatar answered Sep 18 '22 02:09

Carr