Instance variable vs module-scoped variable - javascript

The following components will yield the same result:
const currYear = Date.now().getFullYear();
class App extends React.Component {
render() {
return <MyComponent year={currYear} />;
}
};
class App extends React.Component {
constructor() {
super();
this.currYear = Date.now().getFullYear();
}
render() {
return <MyComponent year={this.currYear} />;
}
};
Assume the variable never changes.
Can their application be considered equivalent?
If not, are there situations where one should prefer the one method over the other?
Been curious for a long time, but never found a solid answer.

In this particular case they are equivalent, primarily because App is supposed to be instantiated once.
This wouldn't be true for a component that is instantiated multiple times. If a user changes system time or a new year comes in, this.currYear changes in future component instances, too.
Using constants as class fields provides more flexibility. There may be a need to change them during tests, this may improve testability. And can be changed in child classes when needed. Even if you didn't design the class to be extendable, another developer may benefit from extensibility:
class BackToTheFutureApp extends App {
currYear = 1955;
}

The first component defines a global javascript variable which could clash with something else (third party components or scripts that may be present). If another component or script also defines this variable you will get a run-time error. If this is the only instance in the whole application (including any other components you use) then it will be no issue. Still, it is somehow cleaner not to define global variables.

Inside of your constructor means that for each instance of your component you'll also have an instance of that variable. I'd imagine you'd be better of using it as per your first example because that will create just one variable no matter how many instances of your component their are. It's also worth noting though that if you take this approach and your program is running for more than a year that it may at some point be incorrect.

first let us answer following question. By answering which we make correct choice.
Will currYear variable be used by other components other than App if no then it should be implemented inside App Component.
Why you may ask:
1.For code readability by other developers.
2.To make it obvious that currYear is used only by App component and no any other
component.
3.To prevent accidental change.

In the first case:
const currYear = Date.now().getFullYear(); // Date is created here
class App extends React.Component {
render() {
return <MyComponent year={currYear} />;
}
};
currYear is the date when the file was required from other file or included on page.
While on second example you declare currYear when the instance of the class is created, so dates will be different:
class App extends React.Component {
constructor() {
super();
this.currYear = Date.now().getFullYear();
}
render() {
return <MyComponent year={this.currYear} />;
}
};
<App/> // Date is created here
Also the first pattern is very bad in almost all cases, for example if you do currYear.setDate(...) variable value will change in every class without re-rendering view.

Related

React: Storing static variable in state vs render variable

I found a similar discussion to my question here but wanted to dig deeper.
I have yet to find any React documentation that discusses whether static variables (that are unchanging but need to be used for a React view) should be stored as a state variable or be rebuilt each time the component is rerendered.
Let's say that I have a React component that takes in a prop, which is a list, and I want to map this list to a certain output. In my use case I am turning the list into the format for the options my component's select picker will use. Once this list is made, it does not need to change. All options will remain the same for the rest of the component's use.
It feels weird to throw it into state, although it just seems more efficient. Let's go through two approaches.
Approach #1: Store option list in component state.
class Component extends React.Component {
constructor(props) {
this.state = {
options: props.list.map(some => computation)
}
}
render() {
return ( <SelectPicker options={this.state.options} /> )
}
}
Approach #2: Recreate variable upon each rerender.
class Component extends React.Component {
constructor(props) {
...
}
render() {
const options = this.props.list.map(some => computation)
return ( <SelectPicker options={options} /> )
}
}
The latter seems more correct, in that since the options array is never meant to change, it is only meant to be initialized once, and it doesn't make sense to put a watcher on it for being part of state. The former just seems more efficient, as we only compute this value once, rather than recomputing it every single time the component is rerendered. Yes React will compare the state between rerenders, but won't it compare the options list references? Whereas the latter example will completely rebuild a new list? Tbh, neither of these seem like the "clean" approaches to this.
The better option is neither. In your constructor function, set this.options to the mapped array and then access it with this.options in your render method.
class Component extends React.Component {
constructor(props) {
this.options = props.list.map(some => computation);
}
render() {
return ( <SelectPicker options={this.options} /> )
}
}
This avoids creating the same array over and over again. It's perfectly fine to set values on this. directly, the point of state is that if a state variable changes the render method is called again.

Where should I bind methods in React component?

I learn React now and noticed that a lot of people bind their methods in constructor.
Like this:
class MyComponent extends React.Component {
constructor() {
super();
this.myMethod = this.myMethod.bind(this);
}
render() {
<button onClick={this.myMethod}>Click me</button>
}
myMethod() {
// do something
}
}
But I got used to writing something like this:
render() {
<button onClick={this.myMethod.bind(this)}>Click me</button>
}
And I was told by a couple of people that using the second method is a bad experience.
So could you tell me the differences between first and second methods? Any pros and cons? or performance issues?
You are right and what others told you is also right.
You are encouraged to do binding in constructor because constructor gets called only once per component so if you do binding in constructor it creates a new object/function only once in Webpack bundle.js file hence not much impact
You are not encouraged to do binding directly in render because a component renders for several reasons like when you do setState, when your component receives new props so your component will render so many times. So since you are binding directly in render whenever your component renders it will create a new function every time in Webpack bundle.js and your bundle file size will increase and that affects performance when your app contains thousands of components and if you do binding directly in render in every component.
So you are recommended to do binding only in constructor. Hope that clarifies
This results in creating a new bound function on every render call:
render() {
<button onClick={this.myMethod.bind(this)}>Click me</button>
}
Notice that if myMethod is used in multiple places, this requires multiple bind calls and may result in unbound callback if one of bind is missing.
While this creates bound function on component instantiation:
constructor() {
super();
this.myMethod = this.myMethod.bind(this);
}
The second option is recommended.
A decorator like autobind can be used to skip myMethod explicit assignment in constructor.
As explained in this answer, prototype methods with bind have less shortcomings than arrow instance methods and can be generally preferred.
You should bind in the constructor simply because the second way will create a new function every render.
But there's a better way to simply avoid binding. Use arrow function.
class MyComponent extends React.Component {
constructor() {
super();
}
render() {
<button onClick={this.myMethod}>Click me</button>
}
myMethod = ()=> {
// do something
}
}
Let's see how the creator of Redux Dan Abramov thinks about bind vs arrow functions -
Question:
In terms of performance, is there any difference between using arrow
functions and bind manually when using es6 classes? Using arrow
functions the methods are not on the class prototype, it will be on
the class instance only. Using bind will attach the methods to class
prototype. It sounds like bind manually will have better performance,
does that mean we should consider using bind instead of arrow
functions for class methods?
Any suggestions or comments are really appreciated!
So in terms of performance, would you recommend using
class MyComponent extends React.Component { constructor(props) {
super(props) }
methodA = () => { ... } }
or
class MyComponent extends React.Component { constructor(props) {
super(props)
this.methodA = this.methodA.bind(this) }
methodA() { ... } }
Answer:
These two ways of writing it are equivalent. (The second one is
compiled to the first one.)
Using bind will attach the methods to class prototype.
In your example, you still attach the function to the instance:
this.methodA = this.methodA.bind(this)
So they’re essentially the same.
At Facebook, we use the second way (“class properties”) but be aware
this is still experimental, and not part of ES6. If you only want to
stick with stable syntax, then you could bind them manually.
First approach is correct performance wise, because on every render this onClick prop will be pointing to the same object, which is not the case in the second example.
If you look at the below example, you will see when I increment the counter, the MyPureCompOne doesn't render, but MyPureCompTwo does. Because each time time the <App> component renders, MyPureCompTwo props handleClick being assigned with a new function object, and that is why being a pure component shallow comparisons of props are false and it renders. This rendering was not needed. But that is not the case with MyPureCompOne, as each time time App renders, the handleClick props still pointing to the same function object (this.handleClickOne) which was created when the App first time mounted.
class MyPureCompOne extends React.PureComponent {
render() {
console.log("rendring component one");
return <button onClick={this.props.handleClick}>First Button</button>
}
}
class MyPureCompTwo extends React.PureComponent {
render() {
console.log("rendring component two");
return <button onClick={this.props.handleClick}>Second Button</button>;
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
this.handleCountChange = this.handleCountChange.bind(this);
this.handleClickOne = this.handleClickOne.bind(this);
}
handleCountChange() {
this.setState(prevState => ({
count: prevState.count + 1
}));
}
handleClickOne(e) {
console.log("Clicked..");
}
handleClickTwo() {
console.log("Clicked..");
}
render() {
const { count } = this.state;
return (
<div>
<button onClick={this.handleCountChange}>Change Counter</button>
<MyPureCompOne handleClick={this.handleClickOne} />;
<MyPureCompTwo handleClick={this.handleClickTwo.bind(this)} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id='root'></div>
I took this from the eslint-plugin-react documentation:
A bind call or arrow function in a JSX prop will create a brand new function on every single render. This is bad for performance, as it will result in the garbage collector being invoked way more than is necessary. It may also cause unnecessary re-renders if a brand new function is passed as a prop to a component that uses reference equality check on the prop to determine if it should update.
As a side note from me, using this in your JSX can be confusing as well. I encourage you to take a look at this doc: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
You should avoid arrow functions and binds in render. It breaks performance
optimizations like shouldComponentUpdate and PureComponent.
For an excellent read and demo you might want to refer
this.

Storing methods needed in all components

I have a universal app I'm developing for learning purposes. I'm managing the state of my app with Redux, so all my data will be available there. But I want to create some methods that I'm going to use in all my components. The problem is: where should I store this methods?
Adding them to a parent component and passing the methods as props doesn't seem very useful, because this is one of the things that Redux tries to solve. And I'm pretty sure that Redux is not a place for storing methods.
I know I can create a class in a file somewhere, export it, add some methods to it, and when I want to use one method in a component I can call this file, create an instance of the class and call the needed method; but this doesn't look very react to me…
Is there a right way to create methods available for all components?
I've had some success sharing functions between components using an approach similar to the following. I'm not sure this approach will solve your specific use case with regards to cookies, however.
These functions can be stored anywhere and imported wherever required. They accept a component as their first argument, then return a function that operates on the component passed in.
Indicative, untested code follows.
// An event handler than can be shared between multiple components
const handleChange = component => event => component.setState({ value: event.target.value });
class ComponentOne extends PureComponent {
state = {};
render() {
return (
<div>
{this.state.value}
<input onChange={handleChange(this)} />
</div>
);
}
}
class ComponentTwo extends PureComponent {
state = {};
render() {
return (
<div>
{this.state.value}
<input onChange={handleChange(this)} />
</div>
);
}
}

Adding props to constructor as this.prop

I have a number of methods in a React class component. The component itself receives a number of props.
I am wondering if I should take the props and add each of them as this.propName in the constructor and then access the props using this.propName. Here is an example. What is best practice?
const classComponent = class classComponent extends Component {
constructor(props) {
super(props)
this.propA = props.propA
this.propB = props.propB
}
methodA() {
console.log(this.propA)
}
}
Alternative
const classComponent = class classComponent extends Component {
constructor(props) {
super(props)
}
methodA() {
console.log(this.props.propA)
}
}
Official documentation of React.js in State and Lifecycle section says:
While this.props is set up by React itself and this.state has a special meaning, you are free to add additional fields to the class manually if you need to store something that is not used for the visual output.
In your case, most likely it should stay as a prop. Whenever you pass anything as a parameter, which in React.js philosophy would be a prop, it's most likely an ingredient of the visual effect.
Once you create a variable it uses memory and, even if you are referencing a type, like an array or an object, you make your file bigger. Creating new names for variables already accessible to your class/function make no sense, so don't do it.
The way you handled the props does not allow the component to update when it receives new props; mainly because constructor is only called once--at the creation of the component.
A better way to do it is to use Destructuring assignment in the render function:
render() {
{propA, propB, ...rest} = this.props;
//Rest code here, using propA, propB
//However, don't use this.propA, or this.propB
}
If you still like to do the way you want to do, you have to add the following function inside your component, to make your component update whenever it receives new props:
componentWillReceiveProps(nextProps) {
this.propA = nextProps.propA;
this.propB = nextProps.propB;
}
As you can see, unnecessary code had to be included, so I think this is a wrong way to do it!

When should a react component be declared as a function, and not a class?

I'm unsure of when to declare react components as simple standalone functions as opposed to the regular class myComponent extends Component syntax. To use an example from React's docs (located here):
The following is referred to as a "component"
function BoilingVerdict(props) {
if (props.celsius >= 100) {
return <p>The water would boil.</p>;
}
return <p>The water would not boil.</p>;
}
While it appears to merely be a function and is declared like any regular old function. Then in the next paragraph, the following is ALSO defined as a component, and looks more like the way I think a component should look:
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input
value={temperature}
onChange={this.handleChange} />
<BoilingVerdict
celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
What is the difference between these two "components"? Is the first example actually a component if it doesn't inherit from the Component class and isn't being created with React.createClass? I would appreciate somebody explaining this distinction since I couldn't find an answer anywhere in the docs.
When you don't need to use the lifecycle methods and the component isn't stateful you can declare the component as a function. Component lifecycle methods like componentWillMount() and componentDidMount() only can be used if the component is a class that extends Component.
Calculator must be specified as a class-based component because it is dependent upon internal component state i.e. this.setState({...}). Functional components, also known as stateless components do not have a backing instance, thus they are unable to maintain local state in the same way.
Personally, I always try to write functional components as they are arguably easier to test due to their nature of consuming props and returning a tree of ReactElement instances. I will only convert a component to be class-based if it will:
need to manage its own presentation-based state i.e. not applicable to the state of the entire application
benefit from lifecycle methods as a means of improving performance through restricted re-rendering
require references to child ReactElements or DOM nodes via refs
There are two complementary docs from Facebook that explain this quite well:
https://facebook.github.io/react/docs/components-and-props.html
https://facebook.github.io/react/docs/state-and-lifecycle.html
TL;DR a "component" is primarily responsible for representing some DOM. Depending on how your application is organized, your component may or may not need to maintain its own state or have access to the lifecycle methods like componentDidMount or render. In the case that you do need these features, your component should be a class that inherits from React.Component. Otherwise, you can likely get away with writing your component as a plain old function.
If the functional way is more preferred instead of creating classes you could use higher-order components utility called recompose, it has lifecycle HOC.
Small example:
const NewComponent = lifecycle({
componentWillMount() {
this.props.onEnterScreen();
},
})(Component)

Categories

Resources