I've read in a few places that functional components are more lightweight than class components, and from here it sounds like Facebook intends for functional + hooks to be the preferred paradigm for new components.
The problem I see is that with functional components things like class methods get redefined on every render, instead of just once. Is this not an issue, or do the other advantages of functional components simply outweigh this?
Example for clarity:
Class Component
class SignInForm extends React.Component {
...
// Only gets defined when the component is created with `React.createElement`
submit = () => {
// send POST request to get an auth token, etc.
}
render() {
<form>
...
<button onClick={this.submit}>Sign In</button>
</form>
}
}
Functional Component
function SignInForm (props) {
...
// Gets defined on every render, since this essentially *is* the `render` function
const submit = () => {
// send POST request to get an auth token, etc.
}
return (
<form>
...
<button onClick={submit}>Sign In</button>
</form>
);
}
Slowest part in web apps is the rendering. So creating a new function on every render is not a big deal. Also for web apps, build size matter and for functional components, minification works better than as it works for class-based components.
With the release of new features like memo, useMemo, useCallback etc. we can get the same performance as we get with class-based components.
React community is moving towards functional components and hooks which is an indication that functional components are not bad.
Related
When clicking the button, you will see n is getting bigger but the UI remains 1
<script>
let n = 1
function add() {
console.log(n)
return ++n
}
export default {
functional: true,
render(h, ctx) {
return (<div>
<h1>{n}</h1>
<button onClick={add}>click</button>
</div>)
}
}
</script>
Intended Behavior
This is the intended behavior of functional components and the thing that makes them functional. From the docs:
...we can mark components as functional, which means that they’re stateless (no reactive data)
Since functional components are just functions, they’re much cheaper to render.
Explanation
What this means-- and the reason n is not reactive-- is that n is not observable and has no dependency management/watching. This lack of dependency overhead is also the reason for the performance increase of functional components. You get speed at the cost of observability, which is a nice tradeoff if you don't need it. If you do, there would be no reason to use a functional component.
How to proceed
So, you could proceed to simply use a non-functional component, or, reason about whether it's possible to subdivide your functional component further and encapsulate only the reactive portions into a non-functional subcomponent.
Other thoughts
If you manually added observability to your functional component, you would get the behavior you wanted, though there's no reason to do this over using a non-functional component. Notice the use of observable:
import Vue from 'vue';
let state = Vue.observable({n: 1});
function add() {
console.log(state.n)
return ++state.n
}
export default {
functional: true,
render(h, ctx) {
return (<div>
<h1>{state.n}</h1>
<button onClick={add}>click</button>
</div>)
}
}
(Note: You can use render functions in normal components as well. I say this just in case you had a misunderstanding that a functional component was required for render functions.)
I am learning ReactJS and I've learned that there are UI Components and Container Components. The Container Components are implemented using classes extending React.Component and contain state and good old render method, whereas the UI Components are created using functions and they are concerned with UI only as they only take the data from props.
Sample stateless functional components:
const Ninjas = (props) => {
const { ninjas } = props;
const ninjalist = ninjas.map((x) => {
var divStyle = {
color: getRandomColor(),
};
return (
<div className="ninja" key={x.key} style={divStyle}>
<p>Name: {x.name}</p>
<p>Age: {x.age}</p>
<p>Belt: {x.belt}</p>
</div>
);
});
return <div className="ninja-list">{ninjalist}</div>;
};
export default Ninjas;
The same sample as a Container Component
export default class Ninjas extends Component {
getRandomColor = () => {
....
return color;
};
render() {
const { ninjas } = this.props;
const ninjalist = ninjas.map((x) => {
var divStyle = {
color: this.getRandomColor(),
};
return (
<div className="ninja" key={x.key} style={divStyle}>
<p>Name: {x.name}</p>
<p>Age: {x.age}</p>
<p>Belt: {x.belt}</p>
</div>
);
});
return <div className="ninja-list">{ninjalist}</div>;
}
}
So my question is why do we even bother to make a UI component (not using the render method which is used in Container Component) when we could have easily done the same thing as a Container Component.
Functional state-less components (what wrongly you refer as UI Components, all components are UI components both statefull and stateless) are simply a short-hand method to create components that simply render something based on props passed and do not need to keep internal state.
Of course one can always use class-based components which extend React.Component. But why not have a short-hand to save time and space and simplify things if we can. There is nothing forcing you to create functional components, you can always use class-based components, only if you need to simplify and save time and space.
According to Functional vs Class-Components in React article:
So why should I use functional components at all?
You might ask yourself why you should use functional components at
all, if they remove so many nice features. But there are some benefits
you get by using functional components in React:
Functional component are much easier to read and test because they are plain JavaScript functions without state or lifecycle-hooks
You end up with less code
They help you to use best practices. It will get easier to separate container and presentational components because you need to think more
about your component’s state if you don’t have access to setState() in
your component
The React team mentioned that there may be a performance boost for functional component in future React versions
I would add a 5th point that React references (with React 16.3+) which provide functionality to access the DOM nodes directly cannot be used with Functional Components.
In React v.16.8+ useState hooks are introduced which enable functional components to be state-full while still being functional.
Furthermore with the introduction of React.memo higher-order component we can use memoization to avoid re-rendering of a functional component given that it renders same stuff for same props (shallow tested for difference)
I'm making a chat app and want to keep its parts separate.
For example, I have part of code where communication logic is described. So when somebody receives a message addMessage function can be used to pass it to react component:
import { addMessage } from './components/App.Chat.MessageField'
rtc.on('data', (data) => {
/.../
addMessage(message);
});
And addMessaget function is binded method of react component:
export var addMessage;
export default class MessageField extends Component {
constructor() {
/.../
addMessage = this.addMessage.bind(this);
}
render() {
/.../
}
addMessage(message) {
/.../
this.setState(/.../);
}
}
So far, everything worked well. But I doubt that's good solution. Can it cause some problems or is there any better ways to do it?
This will lead to bugs. If you invoke setState on an unmounted component React will throw an error. In your example it means that if you are not in the case where MessageField is never unmounted then at some point addMessage will throw. Of course your app should not rely on any of your component never unmounting as it is a core part of the react's semantics.
A better way to do this could be to use redux and have the "add message" behaviour refactored around using redux state and actions. Your rpc.on snippet could be also put inside its own middleware.
We're trying to customise the arguments of a HOC (specifically react-graphql). Due to how this particular library HOC works, we have no ability to influence the component state (queries and options) after the HOC is called.
In a traditional HOC factory like connect() in Redux, all contained logic is applied immediately - which is too early for us. Instead, I'm deferring application of the original HOC (applyOriginalHOC()) until the construction of the first instance from this component.
export function applyLazyHOC(args) {
return function wrap(WrappedComponent) {
let ComponentWithLazyHOC; // Closed-over value is scoped to component
class LazyHOC extends Component {
constructor() {
super();
// Lazy initialising of HOC to give customisations an opportunity to be registered
if (!ComponentWithLazyHOC) {
ComponentWithLazyHOC = applyOriginalHOC(
// Adds customisations which have been registered by third party code
myCustomization(args)
)(WrappedComponent);
}
}
render() {
return <ComponentWithLazyHOC {...this.props} />;
}
}
return LazyHOC;
};
}
It seems like a slightly unconventional approach, so I'm looking for feedback:
Can you see any side effects of changing the initialisation order of HOCs? I'm assuming HOCs shouldn't rely on the presence of other HOCs.
Static analysis (e.g. in IDEs) isn't possible with HOCs anyway, so a lazy evaluation doesn't make this any better or worse, right?
HOCs can provide context to React components, which accumulates across nested components - the order shouldn't matter, right?
A component definition never gets unloaded, and ComponentWithLazyHOC is only created once per component (not component instance). Can you see any potential for memory leaks?
I'm trying to understand stateless components and what the difference is between these examples:
class App {
render() {
return (
<div>
{this.renderAFunction('hello')}
</div>
);
}
renderAFunction(text) {
return (
<p>{text}</p>
);
}
}
and this:
class App {
render() {
return(
<div>
<RenderAFunction text='hello'/>
</div>
);
}
}
const RenderAFunction = ({text}) => (
<p>{text}</p>
);
Or if there is any difference at all?
Functionally, there is absolutely no difference. Both end up rendering a paragraph element, but there are other aspects to consider. There are three points to make (in my opinion) when examining both methods:
Reusability: You have to understand to separate components when you need to. If renderAFunction is just meant to generate some JSX based on, for example, an API request, then it's fine being in a method. But if you want to reuse it somewhere else, then separate it into it's own component. A huge part of React is component reusability and getting rid of code duplication. Separating the method into it's own component would be imperative to accomplish this.
Purpose: There are reason to use stateless function components and reasons not to. The whole point of stateless functional components is to not have state and be presentational. If you need to do something that involves the React lifecycle or internal state, keep it as a method, or new class depending on if you want it reusable.
Performance: Using a stateless functional component would be less efficient. This is because it's a component, not just some JSX returned from a method. As of right now, the React team plans on making some optimizations for stateless functional components because they do not contain state and are merely presentational, but this probably won't happen until after React Fiber is done and thus your stateless functional component has no optimizations versus a regular full-fledged class component. That makes it incredibly inefficient versus a method returning some JSX, especially if it's just used once in another component.
A good rule of thumb is to ask yourself, do I need it anywhere else? If not, then keep it in a method. If you don't need it anywhere else, separating the JSX into a separate component would have worse performance and wouldn't follow React's core principles.
If you are going to need it somewhere else, then separate the component so you follow React's concept of reusability.
Your App's render function will be translated into following JS code for your first example:
render() {
return React.createElement(
'div',
null,
this.renderAFunction('hello')
);
}
And the following one for the second one:
render() {
return React.createElement(
'div',
null,
React.createElement(RenderAFunction, { text: 'hello' })
);
}
While they both looks almost the same, there is one significant difference: laziness. React will execute RenderAFunction body only in case it gonna be mounted to the DOM hierarchy.
It is insignificant is your case, but imaging following example:
const LazyApp = () => {
const heavy = <div><HeavyStuff /></div>
// ...
return <div>done it</div>
}
const HardWorkingApp = () => {
const heavy = <div>{HeavyStuff()}</div>
// ...
return <div>done it</div>
}
const HeavyStuff = () => {
// ... do heavy rendering here
}
Lazy app will not perform any heavy stuff at all. Maybe it is not very clear from that synthetic example why one would do anything like that at all. But there are real-world examples out there, when something conceptually similar (creating Components without rendering them) is happening.
Basically, both will serve the same purpose. But the real advantage of creating a component is its reusability.
If you have to render that particular piece of jsx just for this component. Then, there is no need to create a separate component.