There’s a pattern I’ve seen in a lot of class components that doesn’t fit as well in a functional component: every time the component needs to render some new bit of JSX, create renderThing(), renderOtherThing(), etc, ad infinitum. These just don’t happen in functional components. Technically, you could create an inner function, but people just don’t seem to do it as much. They create a new component. Or at least, in my team, the resistance to breaking that stuff out to separate small components was much lower than with class components. It took very little effort in code reviews to push people towards small components and do it consistently.
Funny that you mention this, because part of the problem was that someone had made a fully functional wrapper around the component. Someone else made a second class wrapper around the functional one because the component has text so state is needed. I wrote out the functional wrapper entirely and kept maybe one of the functions in the class wrapper
Now I think a great many things can be made functional in JavaScript, but purists ruin this for everyone else.
The arguments against JSX and React requiring many small components are very surface level and sound like "we couldn't figure out how to make it work for us so it must be impossible".
1. This was mentioned already, but, yes, you can use ternaries and boolean logic for simple conditionals (loggedIn && <a>Logout</a> || <a>Login</a>)
2. When you need more markup, put them in an if-else statement in the same render function.
render()
if (loggedIn) {
var login = <a>Logout</a>
else
var login = <form onSubmit={ ... } />
return <div>
{ login }
</div>
3. With SFC it's trivial to split these out into new components. You can even use bound methods to reuse the component state and props.
There's a continuum of ways you can structure your code, it just takes some experimentation to find what works for you.
After working with Angular templates for a long time and then switching to JSX, I'm never going back to having my markup in a string blob with magical attributes that make it do stuff.
And I wish I had a reference for this, but I seem to remember reading that any future performance optimizations that could be applied to function components could probably also be applied to class components (at least ones that contain only a render() function and nothing else).
In any case, I'm hoping that React eventually gets to a point where developers don't have to make a choice between class and function components, and the compiler or the runtime makes that decision for us on a per-component basis.
EDIT: As an example, here's a Babel plugin that takes care of the conversion for you at compile time: https://github.com/remcohaszing/babel-plugin-transform-react.... Not sure what its heuristics are for determining what should and shouldn't be converted though, if any.
To a certain extent, I agree that you also don't want overly small components, but it feels a lot like the debate about function size. Sure, you don't want to wrap every statement in its own function, you want functions that are big enough to actually do something useful, but as a rule of thumb, smaller is better than larger.
This isn't a theoretical concern either. Like I said, I've had this issue with Vue before, and component sizes just bloated to the point where many pages were just single, chaotically interwoven components with dozens of state variables that theoretically were never used by each other, but in practice tended to be shared accidentally or out of short term convenience. At which point all bets are off and every bug becomes an exercise in figuring out what's going on.
That's not to say that that's a Vue-specific problem, because I've also had that issue in other frameworks, including React. But far less often in React, because it's much easier to deal with the pain when it starts with a simple refactor, than dealing with it a year and several new features down the line when everything is tangled together like a headphone cord in your pocket.
>Conceptually, a component seems better represented by an object/class than a procedure/function.
In other paradigms, it is! Our paradigm is exploring the functional take. I agree it's a bit unorthodox but we are very intentional about modeling it that way. It really has a bunch of powerful properties one might not expect.
>And aren't classes just really functions under the hood anyways?
The key difference is that in React, UI is a pure projection of current data (props/state). You're always supposed to "return" the UI. Sure a class is a function, but that function is invoked once. Its methods can be called many times, but having a pure render() method (like in class-based React) is really a class cosplaying as a function. Functions are more honest to what React is trying to be.
> Classes may seem like the ideal thing to hold state since that's what they're designed for. However, React is more written like a declarative function that keeps getting executed over and over to simulate it being reactive. Those two things have an impedence mismatch and that keeps leaking when we think of these as classes.
>Another issue is that classes in JS merge both methods and values on the same namespace. This makes it very hard to make optimizations because sometimes methods behave like static methods and sometimes behave like values that contain functions. The Hooks pattern encourages the use of more statically resolvable calls for helper functions.
>In classes, each method has its own scope. It causes issues like us having to reinvent default props so that we can create a single shared resolved object across those. You also encourage sharing data between those methods using mutable fields on the class since the only shared thing is this. This is also problematic for concurrency.
>Another issue is just that the conceptual mental model for React is just functions calling other functions recursively. There is a lot of value to express it in those terms to help build the correct mental model.
For a concrete example of where classes as a model fails us, consider useTransition (https://react.dev/reference/react/useTransition). It lets you start rendering "in background" with a different state value. But if you get interrupted, the renders have the current value. This highlights that in React, the same piece of state can conceptually be thought of having more than a single value (kind of like being in parallel worlds). Classes don't model that well.
I'm all for better solutions for functional components. I hope we go down that road instead of locking in the decision to rely on `class` with things like class decorators and so on.
Several React libraries are already doing that. In spite of all our warnings, people are trying to extend classes for React views, and use `class` in the rest of their code, as well, moving it into the state layer, and modeling their business domains with them instead of using pure functions and Redux.
`class` affords `extends` like balls afford throwing and chairs afford sitting. When you ignore the power of suggestion that comes with the tool affordances, you point users in the direction of trouble.
Sadly, scaling developer education is a lot harder than it seems from inside our ivory towers, surrounded by smart colleagues well-versed in programming wisdom and design patterns.
I have to admit I find the author's insistence on defining a component as a function to be a big red herring. Instead, it feels like the presence of JSX outside of the component's render() method is the (potential) code smell.
It doesn't help that several popular React & React Native tutorials out there, for understandable simplicity, opt to use "renderSubThing" methods. In the examples and in my own code so far, I mostly find those sub-render methods to be a proxy for "I don't want to break stride to make a new component, so I'll jam this stuff in a method and refactor later." That's great, so long as the refactor actually happens.
(Hm, that'd be a great candidate for a vim refactoring plugin...)
This seems at least part of it. And you don’t even really have to learn those things to use stateful React class components, they’re very seldom deeply inherited or require any `this` besides lifecycle methods and their own implementation. Rendered components are not instances.
I know there’s an aversion to classes in a lot of the current React community but the Component design in React was really much easier to reason with.
It's funny React gets bashed in this thread for pushing out createClass crutch, mixins, autobinding into userland, when usually it is being modularity shamed[0].
The change is subtle and easy to misinterpret. It's not that React drank ES6 class kool-aid and we're now gonna use inheritance over composition. (Nope[1], in fact pretty much the opposite[2].)
The real change is that React.createClass is no longer the way to create components. It's just a fancy wrapper (which is not even being deprecated). You want magic, you opt-in to it.
ES6 classes are also not the way to create components. As mentioned at the end of the article, you can even use ES3 module pattern:
React.createClass stops being special/required and becomes a (handy) utility. Can potentially be moved into a separate package.
Competition for mixin systems is now possible.
Finally, this change opens up more possibilities for potential React-like frameworks to “interpret” React components. Of course we don't do that today, but it's still a nice property and may be handy later when you decide to switch to future React-like competitor.
Yeah, that's a fair point. React isn't purely functional, but in practice I'd say it still leans heavily toward a functional approach
You're encouraged to keep state only in top-level components, or in a functional-style state management library like Redux, and pass the data as props/parameters to pure components that are just functions. There's a huge emphasis on immutable data, and composing your various components/functions, passing them as props, etc.
The fact that React switched to using classes makes it seem less functional than it is, and honestly I'm not entirely sure why they decided to do so.
Anyways, you're not wrong, but the point I was trying to make is that React is definitely much more functional than other/older approaches to GUIs, and is popular in (large?) part because of that difference in approach.
Once you understand that function components aren't simple, contained functions but rather components that exist in a parent scope (React) and that React actively manages them, it's not magic at all. Also, you don't need ESLint; the rules are pretty simple.
To me it's all about intent. By using a function instead of a class, you are basically saying "future reader, this component is nothing more than a simple mapping from those values to that DOM tree, don't try to look for internal states or any complex treatment here".
Sure you could write a "normal React component without state" and do the same, but having those properties baked in the way you defined the component is much stronger.
They’re called “function components,” not “functional”, because they reside within a JS `function` as opposed to a class.
The word you’re looking for is side effect. The `use*` family of functions operate as hooks from the component into the renderer, so the renderer can easily see what dependencies a component has. This is accomplished by producing side effects.
The lifecycle methods are all well and good but there was an ergonomic problem with them with shouldComponentUpdate. No one wants to implement that function by hand when it involves whitelisting all props you want to produce a rerender, which is most of them. People would always write bugs. It’s much easier to create a list of dependencies a la second argument to useEffect.
Been bitten by this in React using ES6 where we would sub-class components and override render to provide another layout (or whatever; change behavior).
The right way to do it in React is to define a new Component and make the Component you'd like to depend on wrap around the returned JSX in render instead. Probably not a revolutionary paradigm, but it has made me better at reasoning about and structuring React components.
reply