Right now my app uses functional components exclusively.
I was wondering, if I have a component that should really be a pure component. To get a bit more performance, should I
I rewrite my code to a class component that extends React.PureComponent
Use React.memo HoC to wrap my existing functional component?
Use Recompose.pure HoC to wrap my existing functional component?
or just leave it alone since function components are pure already (not sure if this statement is correct)
This isn't premature optimization, the code is obviously pure, I am just wondering what is the recommended correct way to do it. This isn't really an opinion based thing because there should only be one way to make function components pure.
I'm leaning towards converting to a React.PureComponent, since I am presuming React.memo will use memory regardless where as the PureComponent would have different optimizations.
References:
React.memo performance is worse than with React.PureComponent talks about the performance being worse with React.memo but the answers talk about an improper optimization by uglify.
Recompose pure() vs React.PureComponent talks about how pure is aimed at functional components.
per the comment and announcment by Recompose.pure it appears that it may not be needed at all.
TL;DR: memo
Per the documentation of PureComponents
We recommend to define components as functions instead of classes. See how to migrate.
They have this example
class Greeting extends PureComponent {
render() {
console.log("Greeting was rendered at", new Date().toLocaleTimeString());
return <h3>Hello{this.props.name && ', '}{this.props.name}!</h3>;
}
}
should be
const Greeting = memo(function Greeting({ name }) {
console.log("Greeting was rendered at", new Date().toLocaleTimeString());
return <h3>Hello{name && ', '}{name}!</h3>;
});
They also added this note as a bonus
Unlike PureComponent, memo does not compare the new and the old state. In function components, calling the set function with the same state already prevents re-renders by default, even without memo.
Related
I'm reviewing some code in a React-Redux codebase, and there are quite a few cases where a parent smart component is being passed as a prop to a child component:
import React from 'react';
import Child from '../components/Child';
export default class Parent extends React.Component {
constructor(props) {
super(props);
}
//...
render() {
return <Child parent={this}/>;
}
}
At initial glance, it appears that the intention here is to expose the props/state/methods of the parent to the child component. This sort of goes against many of the design patterns I've used in the past with React, but I'm not sure if it's something that is worth bringing up in a code review (it's already deployed to QA). It technically works (the child is able to call this.props.parent[method], etc) and significantly reduces the lines of code otherwise required if you pass individual handlers/slices of props/(local)state to the child. I know there are downsides (in one case, the parent property shared the same name as a reducer, so in the child component, it is unclear if this.props['reducerName'] is referring to a React Component or a mapped slice of state), but I can't be sure that the downsides are anything more than surface level.
Does something like this run the risk of unnecessary rerenders/diff checks in the child component? Does React ever need to recursively serialize components, and thus incur a lot of overhead because of circular references? Anything I can point out besides I don't think it looks right?
There are a few things I can think of why this might not be a good Idea:
This creates a very tight coupling between the parent and the component. Further, we should try to provide the minimum amount of data to the abstract modules. We call it Principle of least privilege. Here, a lot of information is being passed to the child component which will not be used and can even be abused using a lot of ways.
One case where it can be very bad idea is when the child component changes something on the date object: eg :
render() {
return (
<React.Fragment>
<ChildOne parent={this}/>;
<ChildTwo parent={this}/>;
</React.Fragment>
)
}
Now the ChildOne component can do something like :
this.props.parent.clickHandler = this.anotherHandler
This will break ChildTwo functionality.
Say I want to create a Simple React component with some methods (no state or life-cycle methods). I can do it one of two ways:
// Foo.js
class Foo extends React.Component {
doSomething() {
// do something
}
render() {
...
this.doSomething();
...
}
}
export default Foo;
Or I can do it like this:
// Foo.js
const doSomething = () => {
// do something...
}
const Foo = () => {
...
doSomething();
...
}
export default Foo;
The second is preferable because it's a functional component (simpler, less overhead), but does the closure function come with any overhead / risk of memory leaks?
In general, if a component doesn't keep state or use life-cycle methods, which is the preferable way to implement the component?
Generally, if you:
Do not want to maintain state
Don't need to use lifecycle methods ( like componentDidMount )
it's better to use stateless functional components, which are fast and more readable. And no, you needn't worry about memory leaks due to closure. For more benefits of stateless components, see https://hackernoon.com/react-stateless-functional-components-nine-wins-you-might-have-overlooked-997b0d933dbc
There is no need to use class-based components if you are not keeping track of application state or life-cycle methods simply because it is a lot of overhead, and you don't need to keep track of the this keyword, which is frankly, annoying.
A functional component is dumb. It has no idea of the application state at all. It can be used to display / present the component without having to worry about updating itself when an event is emitted.
In your case, if the doSomething() method does not involve any dynamic behavior, it is preferable to go with the second approach.
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)
I know the difference between stateless and statefull components in react application. I want to know what is the efficient way to use stateless and statefull components together. Is there any performance benefit of using the one over the other in any particular situation
You should default to using stateless components. Since they use no state, it's very easy to tell when a component should be re-rendered, since they will display the same thing if their props do not change.
You should use stateful components when you need to use setState or when you need to use lifecycle hooks.
In theory there could be performance benefits for using stateless components due to the fact they are pure functions (or should be pure functions), but I don't have any hard numbers for that.
Class Components
Class components (that have state) can be used when you want to store some local data inside a component. For eg -
import React from 'react'
function handleInc (state, props) {
return {
count: state.count + 1
}
}
class App extends React.Component {
state = {
count: 0
}
handleClick = () => {
this.setState(handleInc);
}
render() {
return (
<div>
<button onClick={this.handleClick}>Increase</button>
<p>{this.state.count}</p>
</div>
);
}
}
These components are also called smart containers or components because they hold all the logic for modifying the UI based on the state (Redux pattern).
Functional Components or Stateless Components
Functional components have no state or any local data. These components can be used to update some UI by passing down the props from the parent component.
<Child data={this.state.count} />
Functional components have their own advantages like :
They are easy to test.
They are easy to understand.
Performance
No worries about the this keyword.
If anything more, refer to this article.
While working on my first large React application, I started feeling uneasy about the tight coupling of nested components, especially when writing unit tests.
If is a high-level component, and its render function returns <div><Bar><Baz /></Bar></div>, I would like to be able to test Foo, Bar, and Baz in isolation.
I searched for advice but didn't find any. So, on my own, I came up with two methods of injection: factory functions and via the outer component's properties. (I am not talking about Children. I'm talking about "baked in" dependencies--the sort people usually import via require or import statements.
Properties
const Baz = React.createClass({
render() {
return <p>Inner</p>;
}
});
const Foo = React.createClass({
render() {
const Bar = this.props.innerComponent;
return <Bar />;
}
});
ReactDOM.render(
<Foo innerComponent={Baz} />,
document.getElementById('container')
);
Factory
const Baz = React.createClass({
render() {
return <p>Inner</p>;
}
});
const fooFactory = innerComponent => {
return React.createClass({
render() {
const Bar = innerComponent;
return <Bar />;
}
});
};
const Foo = fooFactory(Baz);
ReactDOM.render(
<Foo innerComponent={Baz} />,
document.getElementById('container')
);
Or am I just taking decoupling too far? I see almost no one else doing this in any tutorials or examples.
Would you be inclined to inject components sometimes but not other times? In what circumstances? And, if you did it, would you use one of the above techniques or do it some other way?
This is a pattern you'll see from time to time when there is a run-time necessity for specifying a component type which the component it's passed to will instantiate itself; for example, the React TransitionGroup component takes such a property called component:
By default ReactTransitionGroup renders as a span. You can change this behavior by providing a component prop. For example, here's how you would render a <ul>:
<ReactTransitionGroup component="ul">
...
</ReactTransitionGroup>
Every DOM component that React can render is available for use. However, component does not need to be a DOM component. It can be any React component you want; even ones you've written yourself! Just write component={List} and your component will receive this.props.children.
It's less common to use this pattern for the user-specified contents of a component, since this is solved more elegantly by this.props.children.
However, as far as testing is concerned, the common solution is simply to export each component separately and test it in isolation. If a high-level component composes them in a certain way, all you really need to test is that they are composed properly, since the components are also tested individually.
There is a common pattern of separating "smart" and "dumb" components; dumb components simply render what they're given, and are very easily unit tested. Smart components may fetch data (e.g. via Ajax, or from a flux store), compose specific dumb components, or make other "decisions," and can be tougher to test—but again, since the dumb components are already tested, ideally you can just check that the smart component behaves correctly and renders the right thing.
To use your example, it's Foo's job to render <div><Bar><Baz /></Bar></div>; it's a smart component, and the test should ensure that it renders exactly that. Bar's job, however, is to render its children, and is more easily tested.
You also have the ability to mock out a component with TestUtils.mockComponent.
Check out mochajs. This testing framework overrides import / require, which solves your problem.
It does mean that your subcomponents need to be written as ECMA 6 or NodeJS modules, though - but that really just means they need to be in separate source files.