Pure ReactJS Components - javascript

Dan Abramov says
...a component is pure if it is guaranteed to return the same result given the same props and state.
So if a component is supplied with the same props the same output will always be returned. This is clear.
He then says
pure components... don’t rely on deep mutations in props or
state, so their rendering performance can be optimized by a shallow
comparison in their shouldComponentUpdate() hook
But this means I could supply a pure component with the same props object, but with a difference located deeper inside said props object, and the component would render the same but for different (albeit a deep difference) props. This means this constraint is not enforced.
Is declaring a component as extends PureComponent really saying to ReactJS "I know what I am doing. I guarantee I am using immutable state. So you need only perform shallow props comparisons in shouldComponentUpdate"?
Finally, PureComponents provide a shallow shouldComponentUpdate method by default - presumably this can be overridden with whatever you want (even a deep comparison)?

Is declaring a component as extends PureComponent really saying to
ReactJS "I know what I am doing. I guarantee I am using immutable
state. So you need only perform shallow props comparisons in
shouldComponentUpdate"?
Yes
Finally, PureComponents provide a shallow shouldComponentUpdate method
by default - presumably this can be overridden with whatever you want
(even a deep comparison)?
You can override it. React will try to warn you not to do so. In this case its better to inherit from Component instead.

https://medium.com/groww-engineering/stateless-component-vs-pure-component-d2af88a1200b
class Welcome extends React.PureComponent {
render() {
return <h1>Welcome</h1>
}
}
Hello = () => {
return <h1>Hello</h1>;
}
So above there is an example of a very simple Welcome Pure Component
and Hello Stateless Component. When you use these two in your Parent
Component, you will see Hello will re-render whenever Parent Component
will re-render but Welcome Component will not
Also in cases where you want to use lifecycle methods of Component
then we have to use Pure Components as stateless components don't have
lifecycle methods.

Please read about Pure Render Checks
https://github.com/vasanthk/react-bits/blob/master/gotchas/01.pure-render-checks.md
and good articles there :
https://flexport.engineering/optimizing-react-rendering-part-1-9634469dca02
https://flexport.engineering/optimizing-react-rendering-part-2-7b2e9a9ea21f
https://flexport.engineering/ending-the-debate-on-inline-functions-in-react-8c03fabd144

Related

Should I wrap all my components with React.memo() if it is not expecting any props?

While it is obvious why React does not perform React.memo to all its functional component by default, and we should ourself wrap our functional components as and when needed.
In my case, I have a big react project with a structure like this:
const MyBigApp = () => {
const shouldShowX = useSelector(getShouldShowX);
const shouldShowY = useSelector(getShouldShowY);
// Many more selectors
return (
<>
{shouldShowX && <ComplexComponentX />}
{shouldShowY && <ComplexComponentY />}
{/* many more components based on different selectors like above */}
</>
);
};
All my business logic is inside redux and the components use useSelector internally to get data from the store.
Does it make sense to wrap all my child components with React.memo, as a change in any selector at root level causes my entire app to re-render?
Earlier with connect we were automatically getting a memoized component which was comparing custom props and store value passed as props to the component, so should we now manually always do React.memo while using useSelector in a component not receiving any props?
I would argue that you should consider using React.memo for those child components that don't accept any props. I highly recommend this article: https://dmitripavlutin.com/use-react-memo-wisely/
2.1 Component renders often with the same props
The best case of wrapping a component in React.memo() is when you expect the functional
component to render often and usually with the same props.
Since the components you're asking about don't accept any props, that means the props will never change. Therefore, it stands to reason that using React.memo could avoid render cycles. Note this important caveat from the same article:
5. React.memo() is a performance hint
Strictly, React uses memoization as a performance hint.
While in most situations React avoids rendering a memoized component,
you shouldn’t count on that to prevent rendering.

Is the reason props in React shouldn't be changed/mutated is because React wants elements to be as predictable as possible?

From React documentation.
Conceptually, components are like JavaScript functions. They accept
arbitrary inputs (called “props”) and return React elements describing
what should appear on the screen.
Considering:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
or
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Will give us the ability to do this:
<Welcome name="Luke" />;
<Welcome name="Leia" />;
to use as we wish in the DOM,
Hello, Luke
Hello, Leia
Now when people prescribe props shouldn't be changed, it would make sense the reason is in my thinking would be like the same as changing the values of attributes of an image tag?
HTML:
<img id="Executor" alt="Picture of Executor" src="/somepath/vaders-star-destroyer-executor.jpg"/>
JS:
Meanwhile in a Javascript file a long time ago in a galaxy far, far away...
var imageOfVadersStarDestroyer = document.getElementById('Executor');
imageOfVadersStarDestroyer.src = "/somepath/vaders-star-destroyer-avenger.jpg"
Because if we keeping changing an elements attribute values this can cause confusion and slower renderings?
So is the reason why the prescription is to never change props in React is because is the library is trying to make elements as predictable as possible?
Setting props outside of React is dangerous and should be avoided. Why? The main reason is that it doesn't trigger re-renders. Hence bugs and unexpected behaviour.
Re-rendering
Most of the time, props are data that is store as state in the parent component, which is manipulated by calling setState() (or the second function returned by React.useState()). Once setState() is called, React re-renders and computes what has changed under the hood, with the latest props and state. Manually assigning values to props, therefore won't notify React that the data has changed and something has to be re-rendered.
The good practice
Making props read-only allows React components to be as pure as possible, which is obviously a good practice anyway even when writing plain JS. Data won't be changed unexpectedly and can only be done so by calling setState() (You might have heard of the single source of truth, which is what React is trying to leverage).
Imagine you notice something went wrong in the app and the data shown to the end user is completely different from the source, it would be a pain trying to find out where the data has been manipulated wouldn't it? :)
never change props in React
means that you should never do this.props.name = "userName" because of React's one way data binding, props are read only, to update a component's props, you should pass a function from the parent that will do that ( in the parent ) , or dispatch an action if you're using redux, a change in the props will trigger a re-render
props is a constant in this case. You will always need it in your components.
But there is a cleaner way to write it or even omit it.
Regular way with Function Expression (same as your exemple)
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
ES6 Object Destructing - explicit
function Welcome(props) {
const {name} = pros
return <h1>Hello, {name}</h1>;
}
ES6 Object Destructing - inplicit, cleaner way
function Welcome({name}) {
return <h1>Hello, {name}</h1>;
}
And of course, you can use the class way which requires the usage of this.props.yourAttr
However, in the new version 3 of create-react-app, changed class components to functional components. You can see this exact modification on Github here.
You can need to learn more about destructing assignment in the old and good MDN linked here or an in-depth approach both array and object destructuring here.

how to prevent children component re render, when state/props parent component changing?

right now im have tree component like this
<UserOrderApproval>
<Table>
<TableRow>
<ComponentList />
</ChildrenProps1>
</Parent>
</UserOrderApproval>
im take props from redux in UserOrderApproval component, and passing that props to every children component. The problem, when children component make some change in redux, the state from UserOrderApproval component will change & make all children component re render & make component life cycle run again. How to do prevent this?
How best practice to passing props from parent to nested children like this?
Many Thanks
As KuchBhi said, you'll need to use the shouldComponentUpdate lifecycle method.
shouldComponentUpdate is called any time when new props or state are passed to the component and by default returns true (might only return true for updated props, not 100% sure). The method accepts two parameters: nextProps and nextState. You can then compare these to this.props and this.state to decide whether you should update or not.
The default/typical implementation of this method is something along the lines of this (pseudo):
shouldComponentUpdate(nextProps, nextState) {
//Really it's a deeper equality check, not just the props/state object
return this.props !== nextProps || this.state !== nextState;
}
What you can do as an alternative is build this out a bit more with cases where false is returned. Here is an example from one of my projects where I only want to rerender when two specific props are different:
shouldComponentUpdate(nextProps) {
const minUpdated = this.props.min !== nextProps.min;
const maxUpdated = this.props.max !== nextProps.max;
return minUpdated || maxUpdated;
}
The component also has the props such as scale, align, width, etc. but I don't want to update when I receive those as new props so I don't check to see if they're not equal.
You could essentially just return false in this method and never update after the initial load, but I would avoid that as it defeats the purpose of react.
edit: As varoons said, this is likely a great scenario for you to use the new context API and I highly recommend looking into it, but it is useful to know about component lifecycle methods as well.
Use shouldComponentUpdate(), pure components, or connect redux to only the child components that need them.
https://reactjs.org/docs/react-component.html#shouldcomponentupdate
https://reactjs.org/docs/react-api.html#reactpurecomponent
This is a good scenario to use React's context api as this seems like a prop drilling case - You are passing data down to components that do not use it.
You could make UserOrderApproval(assuming it is the parent connected to the global state/redux) the context provider and ComponentList the consumer. This way only the components handling/using the data will re-render.
https://reactjs.org/docs/context.html
https://scotch.io/tutorials/get-to-know-reacts-new-context-api

How to make props immutable to prevent rerender in React?

I have been creating a small app using react.js. I take 'performance' into account excessively.
So I have a simple child component named "Spinner". My goal is to make sure this component never re-renders.
Here is my component:
import React, {PureComponent} from 'react';
export default class Spinner extends PureComponent {
render() {
return (
<div className="spinner">
<div className="bounce1"></div>
<div className="bounce2"></div>
<div className="bounce3"></div>
</div>
)
}
}
In the time of the re-rendering with 'react-addons-perf', the component is always rendering, I am using PureComponent because I want that component to render only one time, I read that I can use immutable props but I don't know how to make this possible.
If I make some like to this:
componentDidMount() {
this.renderState = false;
}
shouldComponentUpdate(nextProps, nextState) {
return (this.renderState === undefined) ? true : this.renderState;
}
It is rendering only one time, but I believe that there is a better way.
How do I avoid the re-render? or maybe How I can make a immutable props?
You don't need an extra logic for componentShouldUpdate, since you don't want your component to rerender ever.
Adding only this should be enough to prevent component to rerender:
shouldComponentUpdate(nextProps, nextState) {
return false
}
For stateless components that don't need props, we can use a combination of a Functional (stateless) component, and babel's React constant elements transformer to optimize the component creation, and prevent rerenders entirely.
Add React constant elements transformer to your build system. According to the docs the transformer will:
Hoists element creation to the top level for subtrees that are fully
static, which reduces call to React.createElement and the resulting
allocations. More importantly, it tells React that the subtree hasn’t
changed so React can completely skip it when reconciling.
Change the spinner to a stateless component.
const Spinner = () => (
<div className="spinner">
<div className="bounce1"></div>
<div className="bounce2"></div>
<div className="bounce3"></div>
</div>
);
export default Spinner;
You can make your props immutable in React by using Immutable JS to transform your array props into Lists and object props int Maps. With this library you can use simple checks to check the equality of arrays/objects (instead of going through keys/values for equality):
shouldComponentUpdate(nextProps) => {
this.props.complexObjectAsMap === nextProps.complexObjectAsMap
}
But since your component doesn't have any props - this doesn't look the right question. In your case I'd go with Ori Drori answer.

When to use state and when props?

I am studying the principles of react.
According to some reviews, some people says is better to keep your component stateless, what does it mean?
But other people says, that if you need to update your component, then you should learn how to set your state to the proper state.
I saw this.props / this.setProps and this.state / this.setState and I am confuse with that.
Something I am trying to figure is, how can I update a component by itself and not from a parent component? should I use props or state in this case?
I already read some docs about props and state, what I don't have clear, is: when to use one or another ?
Props vs. state comes down to "who owns this data?"
If data is managed by one component, but another component needs access to that data, you'd pass the data from the one component to the other component via props.
If a component manages the data itself, it should use state and setState to manage it.
So the answer to
how can I update a component by itself and not from a parent component? should I use props or state in this case?
is to use state.
Props should be considered immutable and should never be changed via mutation. setProps is only useful on a top-level component and generally should not be used at all. If a component passes another component a property, and the first component wants the second to be able to change it, it should also pass it a function property that the second component can call to ask the first component to update its state. For example:
var ComponentA = React.createClass({
getInitialState: function() {
return { count: 0 };
},
render: function() {
return <Clicker count={this.state.count} incrementCount={this.increment} />;
},
increment: function() {
this.setState({count: this.state.count + 1});
}
});
// Notice that Clicker is stateless! It's only job is to
// (1) render its `count` prop, and (2) call its
// `incrementCount` prop when the button is clicked.
var Clicker = React.createClass({
render: function() {
// clicker knows nothing about *how* to update the count
// only that it got passed a function that will do it for it
return (
<div>
Count: {this.props.count}
<button onClick={this.props.incrementCount}>+1</button>
</div>
);
}
});
(Working example: https://jsbin.com/rakate/edit?html,js,output)
For and object-oriented programming analogy, think of a class/object: state would be the properties you put on the class; the class is free to update those as it sees fit. Props would be like arguments to methods; you should never mutate arguments passed to you.
Keeping a component "stateless" means that it doesn't have any state, and all its rendering is based on its props. Of course, there has to be state somewhere or else your app won't do anything! So this guideline is basically saying to keep as many components as possible stateless, and only manage the state in as few top-level components as possible.
Keeping components stateless makes them easier to understand, reuse, and test.
See A brief interlude: props vs state in the React docs for more information.
Use state when you know the variable value is going to affect the view. This is particularly critical in react, because whenever the state variable changes there is a rerender(though this is optimized with the virtual DOM, you should minimize it if you can), but not when a prop is changed (You can force this, but not really needed).
You can use props for holding all other variables, which you think can be passed into the component during the component creation.
If you have want to make a multi-select dropdown called MyDropdown for example
state = {
show: true,
selected:[],
suggestions:this.props.suggestionArr.filter((i)=>{
return this.state.suggestions.indexOf(i)<0;
})
}
props={
eventNamespace:'mydropdown',
prefix : 'm_',
suggestionArr:[],
onItemSelect:aCallbackFn
}
As you can see, the objects in the state variable are going to affect the view some way or the other.
The objects in the props are mostly objects which should remain the same throughout the component life cycle. So these objects can be callback functions, strings used to namespace events or other holders.
So if you do want to update the component by itself, you need to have to look into how componentWillRecieveProps ,componentWillUpdate, componentDidUpdate and componentShouldUpdate works. More or less, this depends on the requirement and you can use these lifecycle methods to ensure that the rendering is within the component and not in the parent.

Categories