Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should you define all properties of a component's state inside the constructor?

So I finished reading this article which basically talks about how v8 and other javascript engines internally cache the "shape" of objects so that when they need to repeatedly access a particular property on an object, they can just use the direct memory address instead of looking up where in that object's memory that particular property is.

That got me thinking, in React you often declare a component's state inside the constructor but don't include all the properties that will eventually be included in the state, for example:

class MyComponent extends React.Component {
   constructor(props) {
       super(props);
       this.state = {
          hasLoaded: false
       };
   }

   componentDidMount() {
       someAjaxRequest.then((response) => {
           this.setState({
              content: response.body,
              hasLoaded: true
           });
       });
   }

   render() {
       return this.state.hasLoaded ?
          <div>{this.state.content}</div> :
          <div>Loading...</div>;
   }
}

Since according to the article, the state object doesn't remain a consistent structure, would doing something like this be less efficient than defining all the possible state's fields in the constructor? Should you always at least add all the properties even giving them a value of null so that the object is always consistent? Will it impact performance in any substantial way?

like image 527
MarksCode Avatar asked Jul 13 '18 21:07

MarksCode


People also ask

Why should you avoid copying the values of props into a component's state?

Don't “copy props into state.” It creates a second source of truth for your data, which usually leads to bugs. One source of truth is best. Components will already re-render when their props change, so there's no need to duplicate the props as state and then try to keep it up to date.

Can we declare state outside constructor?

By using an alternative class syntax, you can leave out the constructor and initialize the state as class field declaration. However, you don't have access to the props anymore.

Is it necessary to have a constructor in every component?

It is not necessary to have a constructor in every component. It is necessary to call super() within the constructor. To set property or use 'this' inside the constructor it is mandatory to call super().

How do you define a constructor in React native?

The constructor in a React component is called before the component is mounted. When you implement the constructor for a React component, you need to call super(props) method before any other statement. If you do not call super(props) method, this. props will be undefined in the constructor and can lead to bugs.


2 Answers

TL;DR The performance wins seem to be negligible enough to not really be worth it.

Test setup:

I made 100,000 children of this class:

import React, { Component } from 'react';

const getRand = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;

class Child extends Component {
  constructor() {
    super();
    this.state = {
      loading: false,
    };
  }

  componentDidMount() {
    const key = getRand(1, this.props.numKeys);
    this.setState({
      key,
      [key]: 'bar',
    });
  }

  render() {
    if (this.props.display) {
      return <div>child {this.state.key} {this.state[this.state.key]}</div>
    }
    return <div>child 0</div>
  }
}

export default Child;

The children are made as follows:

const children = [];
for (let i = 0; i < 1 * 100 * 1000; i++) {
  children.push(<Child display={true} numKeys={1000} key={i} />);
}
return (
  <div>
    {children}
  </div>
);

The idea being: I could pass in the display prop to either render the same HTML for every child, or a different HTML.

I also passed in a numKeys to determine how many different types of keys there should be on the object. After testing, the display prop didn't significantly affect the DOM render time, so I didn't report it below. All tests were run with yarn build && serve -s build via create-react-app

Results

Same key for all children

Same key for all children

3 keys for all children

3 keys for all children

10 keys for all children

10 keys for all children

1000 keys for all children

1000 keys for all children *all tests in Chrome 67.0.3396.99

As you can see, the performance for 100,000 objects is negligible until you have a lot of different shaped objects. Even then, your performance increase is 700ms over 100,000 components, or 7 microseconds per component. It's certainly not the 8x speedup claimed.

MOREOVER: Your render time is likely to be dwarfed by DOM actions in anything realistic, and not synthetic like this test.

like image 62
AnilRedshift Avatar answered Oct 19 '22 22:10

AnilRedshift


Optimizations aside, it's a good idea to model all local state fields even if it's just data: null as you mention. This way, you can reset the component back to it's initial state with a simple call to this.setState.

like image 28
Danny Delott Avatar answered Oct 20 '22 00:10

Danny Delott