How Does React Tell a Class from a Function?
overreacted.io
overreacted.io
https://medium.freecodecamp.org/7-reasons-to-outlaw-reacts-f...
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.
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.
This makes me very skeptical about the proposed feature in React, called "hooks", which is linked to in the article. It lets you add state to your functional components, and it looks like you end up bundling all your code into one function rather than having a separate constructor to initialise the state (to me, separating out that function is a good thing). I would be interested in the motivation for that.
To us, too, and that's exactly the point of Hooks. They let you extract logic into functions in a way that wasn't possible before. I suggest to read more than a single page -- in particular, extracting custom Hooks is largely the point of the proposal.
https://reactjs.org/docs/hooks-custom.html
I also wrote about this here:
https://medium.com/@dan_abramov/making-sense-of-react-hooks-...
https://gist.github.com/gaearon/cb5add26336003ed8c0004c4ba82...
Without hooks, that example would require adding a method (or two) to the component class. With custom hooks, that code can go into a separate module.
Component bloat has been a problem for us, and if hooks can enable components to focus solely on render logic, I'd say that's an improvement.
class WidthStore {
width: stream.Stream<number>;
constructor() {
this.width = stream(window.innerWidth);
window.addEventListener('resize', () => {
this.width(window.innerWidth);
m.redraw();
});
}
}
const widthStore: WidthStore = new WidthStore();
class MyResponsiveComponent {
view(vnode) {
return <p>Window width is {widthStore.width()}</p>;
}
}The article you link to actually explains that quite well. Basically there are three motivations for hooks:
1. Keep code that belongs to one functionality in one place. For example setup and teardown would be in the same hook, but when writing a class they are scattered among the many things happening in the event methods in the class
2. Allow new ways to compose functionality. You can use the same hook in different functions. You could achieve the same effect before, but this makes it more convinient
3. Produce code that works better with Prepack [1], to make ahead-of-time compiled react runtimes more efficient. It might be some time until this becomes a rolled out advertised feature, but hooks are a good step on the way there
Hooks will allow people to use "class like" features and behavior, but with none of the conventions forced by syntax, plus some pitfalls.
To me it seems a good way to ensure most devs (espacially unexperienced casual ones, which are legions in JS by nature of the market) will dump their logic wherever it works with as little structure as it allows. It's a technical debt catalyser, and will make sure nobody feels at home in someone else's code. The community will pay the price in a year.
It's also yet another way to do the same thing, and JS has already a lot of those. React as well. Documentations, tutorials and examples will suffer from it. But again, it's very common in JS land where learning anything requires gathering scattered puzzle pieces then assembling them, hoping they are from the same set this time. It allows me to bill more, so I'm not complaining, but it's not fair to newcommers.
Note that I can see some nice things about hooks. I just strongly think they don't outweight the cost by an order of magnitude.
FB idea of ergonomics and user friendliness, in API and UI, has always been to force their way into things, until it blocks, back down, and fix things when possible or use a workaround.
Having been training people in web tech for years, the consequences of such policy show in the classroom. But, hey, more money for me :) Plus when I dev, I have the experience to avoid the pain, mostly knowing when not to do or use things. But I can tell than many of my younger colleagues don't, and a few of my not so young ones too.
Still, I wish they gave a bit more though to this aspects of their products: their are brillant technicians, so it's not that they can't, it's just a matter of culture.
One of the key reasons for choosing a framework/library is to enforce (reasonable) constraints. These constraints help in making sure that the framework takes a longer term view of things than just making it easy in the short term.
I don't want to downplay your concerns, but I will say that this is already a problem. Part of the goal with hooks (and I can't say if it achieves that) is to encourage the separation of a lot of state-interaction OUT of the components. Today it is much too easy (arguably it is easiest) to write a component that is basically untestable - basically a mini-application in itself, which is the opposite of good React design.
I'm hopeful that Hooks will help, and I think the original demonstration focused too much on state and not enough on other interactions external to the component, which is where the real pain today exists. I've not played with the alpha at all to have a feel for how realistic my hopes are.
React seems like it’s getting more complicated every single day. I loved it due to its simplicity but now i’m not so sure.
If preventing people from being confused and doing the wrong thing was the goal, I'm not sure adding one new way to the mix is going to make things clearer.
Besides, while I agree tooling help with applying good practices, including encapsulation, it's no substitute for a good initial API design.
React and JS API are confusing, because they have been designed this way from the start. We are now adding things on top of it, again and again, without ever fixing anything at the bottom. This creates problems at the same time it solves others.
Another issue is that the JS community wants to professionalise without aknowledging that a huge part of it doesn't have the skill to do so yet. It's a community that includes many young devs with little experience, people that are not programmers but ends up doing so, devs born in a culture of instant results... It's important to address this as well, by talking to them in tutorials and documentation, by creating API shaped with them in mind, so that they can grow in empowering directions.
Instead, we create monster trucks, and they put ads on youtube to tell everyone how "easy it is to drive" and "you should do it too right now".
For me, hooks are a monster truck. And most JS devs I work with are not capable of driving that safely.
Nothing wrong with your comment on trying to embrace it per se, but it would be healthier if this sentiment was balanced in the community with more skepticism rather than blind embrace.
I get that, but I'm not sure it's in the interest of most projects either. The vast majority of React code base can (and IMO should) do the simplest things instead of going with a store. Redux and other means of putting state interactions out of components are a huge overhead in so many ways that I think it should be the exception, not the rule.
Besides, even for fluent react devs, it is a common strategy to create applications as a big fat component that does it all, then split it little by little into smaller parts as the need arises. Complexity management is hard after all.
It makes sense the FB team wants to promote a pure clean industrial flux pattern, so I understand why they go this way. I just note they are doing so, ignoring the fact the vast majority of devs work on code that never reaches anything close to their requirements. And if it ever does, it certainly doesn't start that way.
Same goes for tests. I'd say only one projects out of give I work on are decently tested. Our industry has low quality standards it seems. But creating something that will cause confusion among the less skilled in hoping it will help the experts do fewer mistakes is not a good trade off: IRL teams have one 10x programmer for many more regular ones, if at all.
Again, I follow the logic. I just think it's not a good bet for the community. It may be a good bet for FB scale entities, but I'm not even sure it is.
From the Rules of Hooks section in the documentation[0].
- React relies on the order in which Hooks are called. - Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions. - Only call Hooks from React function components. Don’t call Hooks from regular JavaScript functions.
This design decision doesn't sit well with me, and I won't be using it. However, the community seems to have already welcomed it, so I'm forced to learn the intricacies to be able to understand React codebases and keep up with the latest trend..
The addition of this feature is sure to increase cognitive load and technical debt. There are already countless variations of state management libraries and patterns that encourage pure functional components and decoupled logic. Hooks seem to be yet another opinionated strategy - and not for the best, in my view.
---
That's one thing that no many realizes: the JS community is special and you should take that in consideration when adding a new features.
When I say special, I mean it reacts (puns intended) in a way no other programming community does:
- it jumps on novelty with very little afterthoughs or regards for consequences.
- it has an habit of disregarding lessons from the past.
- it seldom fix problems, but add a new layer of solution on top of it.
Knowing this, the way hooks are released is too me like giving matches to children with the only advice "look how cool it is, I can make fireworks".
Yes, I'm exagerating for the argument sake. But still, react is now a software used everywhere, I'd welcome a switch from "move fast and break things" to "let's think this true" once in a while.
The line between React and vanilla code is blurring more every day - which is a bit greedy for something that's purely meant to be a rendering solution. I would personally advocate to push React as far away from my app code as possible, and instead implement a specialised container class that hooks into React's internals (Controller? Model?) purely to handle localised state changes.
It seems the React team intends to completely move away form using classes.
See hooks
Intent: it makes clear that the component is stateless in a way a class-based component does not.
Later they added function components because they are more concise and tell readers that this component is a simple mapping from props to virtual DOM elements.
With hooks, a recent addition to React, they seem to move away from class components. Hooks enable you to use state and do things when a component is mounted in the DOM or removed from it inside of function components.
I always thought that you could just write valid JavaScript and it's completely Babel's responsibility not to screw that up.
Edit: not sure what's wrong with my comment so let me clarify:
I wouldn't have thought that library developers had to think about what other tools might do with their library. I always thought that so long as your code is valid JavaScript, Babel would faithfully transpile it down to another valid target using polyfills and whatnot.
For what it's worth, if we found while developing React that Babel was compiling something in a problematic way and we had a better suggestion for the compiled output, we'd certainly see if we could get it fixed upstream. In this case the Babel output for classes is pretty reasonable so there's nothing to change.
We did briefly consider if it made sense to require every function component to be written using an arrow functions and asking Babel to delete the .prototype property from every compiled arrow function (compiling a = () => ... into something like a = function() { ... }; a.prototype = undefined;). We eventually decided that the .prototype.isReactComponent compromise described in the post was a better result overall, both for authoring ergonomics and runtime performance.
Well, I think how prototype works is much more important than using React.
I think having an interview in JS without knowing prototype is like having an Java interview without knowing polymorphism, abstract class, interface or something.
Although I'd also note that in practice people tend to use a subset of JS in their work, and often prototypes aren't directly used. (I understand they power everything under the hood but I'm talking about something product engineer has to think about.)
Prototypes are more powerful than anything Java has to offer.
It's a low-level concept that is mostly used to create a class system on top of it, rather than used directly.
Polymorphism, abstract classes or interfaces are part of the day-to-day stuff a Java dev has to meddle with.
If you are just building frontend applications using frameworks like React and Vue, you don't really need to know how things work under the hood. Especially with all of the new syntactic sugar introduced to JS in the last few years.
But, if you are building lower level tooling and you want to understand why things are implemented the way they are (this post being a great example) you really should understand them as best you can. A lot of design decisions in JS are influenced by these lower-level design "constraints."
However, when it comes to a mid or senior level engineer, it's important not to just make things work, but to understand the how and why in order to build performant applications at scale.
So to answer your question, no it's not a necessity to build applications. Yes, it is if you want to excel at building applications.
You can absolutely be a great javascript developer without ever touching prototype. Prototype is an infection of object-oriented programming into a functional language.
You can use it if you want to, but it has never been popular in C++, and in 20 years I have never encountered a problem that could be solved by using it, so I have never used it. And in C++ bind is part of the functional programming paradigm, as it does currying, not much to do with classes.
Bind in JavaScript makes your shoehorned collection of attributes actually behave like objects. We can see JavaScript's bind used everywhere.
class C {
handleEvent() {}
someMethod() {
onEvent(this.handleEvent); // bad; "this" lost
onEvent(this.handleEvent.bind(this); // ok
}
}
C++ requires the same thing. The bad case will even generate an error at compile time. class C {
public:
void handle_event() {}
void some_method() {
on_event(&C::handle_event); // bad; error
on_event(std::bind(&C::handle_event, this)); // ok
}
}; function isClass(fn) {
return !Object.getOwnPropertyDescriptor(fn, 'prototype').writable;
}
it relies on the fact that the prototype object of ES6 classes always non-writable.https://babeljs.io/repl/build/master/#?babili=false&browsers...
https://www.typescriptlang.org/play/index.html#src=function%...
I'm guessing the site is built with gatsby from the theme.
You can use https://overreacted.io/rss.xml for subscription.
https://github.com/wisercoder/uibuilder/blob/master/UIBuilde...
> One other possible heuristic could be to check for presence of a render method on the prototype. However, at the time it wasn’t clear how the component API would evolve. Every check has a cost so we wouldn’t want to add more than one. This would also not work if render was defined as an instance method, such as with the class property syntax.
[0] https://www.reddit.com/r/reactjs/comments/a2j6xk/how_does_re...
Feels like yesterday to me. I still do my objects prototype style because classes feel too new and bleeding edge.
Aren't most people hiring frontend developers looking for people who understanding Javascript (and not just React)?
Or is "React" a skill separate from Javascript these days?
Personally, I'd be hesitant to hire anyone who "knows React" but doesn't know the basics of how it works.
In some benchmarks this approach is 20 to 30 times faster than React.
20+ years of confused programmers suggests that maybe it wasn't the right way to go for a language that is frequently used by beginners, but still that wasn't the fault of prototype based programming itself.
The new class system is syntactic sugar leveraging the power of prototypes. This was always possible, and nothing stopped you from implementing a class-like system in JavaScript a long time ago.
More, very readable, info here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guid...
.prototype is the template of newly created objects of the object you are inspecting.
> That’s not what React does though.
>
> One caveat to the instanceof solution is that it doesn’t work when there are multiple copies of React on the page, and the component we’re checking inherits from another React copy’s React.Component.
Real TL;DR: > If you don’t extend React.Component, React won’t find isReactComponent on the prototype, and won’t treat component as a class.>If the final API is successful, its users never have to think about this process. Instead they can focus on creating apps.
If only it worked that way. Unfortunately, somehow I always end up needing to know about the process cause the abstraction leaks like a sieve. And it's leakier in javascript than in any other language.
Some excerpts for those that didn't have the strength to sit through the entire thing without pulling their hair out:
> If you called Person('Fred') without new, this inside it would point to something global and useless (for example, window or undefined). So our code would crash or do something silly like setting window.name.
> However, JavaScript also allows a function called with new to override the return value of new by returning some other object. Presumably, this was considered useful for patterns like pooling where we want to reuse instances:
> However, new also completely ignores a function’s return value if it’s not an object. If you return a string or a number, it’s like there was no return at all.
> And yet I still find it very confusing that a property called prototype does not give you a value’s prototype (for example, fred.prototype is undefined because fred is not a function). Personally, I think this is the biggest reason even experienced developers tend to misunderstand JavaScript prototypes.
> However, some class implementations we wanted to target did not copy static properties (or set the non-standard __proto__), so the flag was getting lost
Edit: And I missed the best/worst one yet: You can have MULTIPLE VERSIONS of the SAME DEPENDENCY running around in your codebase, interacting in ways that only god knows. In retrospect, this should have been obvious from the way javascript "imports" work, but, holy shit! If Satan himself had to design a language, he could not have done a better job. And I'm sure he would not have the stroke of genius required to make it the only programming language you can use if you want to target the most widely available platform for code in the world.
The next time I have to allow NoScript to let some js in, I will wonder how many goat sacrifices went into making the thing work.
Depending on what you are doing, you may have very little react-specific code in your application.
You have data fetching, caching, persistence, authentication, tons of things, not to mention business logic that needs to be implemented in just plain Javascript.
Then out of that process you may have workers or other async background jobs happening which should not involve React at all.
[0]: It may not be required, but it was created for a reason....
There are other templating systems you can use in React if you don't like JSX.
I've seen one codebase use direct calls to ReactDOM.createElement and there is a new hotness (which I can't think of the name of now) that replaces JSX with template literals, something like:
function NamePetList(props) {
return html`
<div>
Hello <b>${props.name}</b>!
<ul>
${props.pets.map(pet => html`
<li ${...pet.props}>${pet.name}</li>`
}
</ul>
</div>
`
}
which I really like.The library parses the strings to figure out which elements to create. Flow control and variables are just normal template literal arguments.
Personally I still use it, but I think it's fair to say that as much as JSX was created for a reason, it's made optional for a reason too.
Put another way: React calls your components, not you. You pass the component function itself to React.createElement, not its result.
JSX prevents you from being able to do this directly. For example, <() => "hello" /> is illegal.
- Write in one language only for both client and server side. Why is good? You just need js devs, no need to duplicate validation and other logic. I'm making a game right now and has js on the backend. I want to make the game single player, now I can just import a file from the client side and <<Boom!>> now is single player. If your backend is in java, good luck to make it single player.
- Compare a website to an installable app. Who is more likely to gain more customers all things being equal? If you click on a link from google, is more likely to browse a website rather than installing an app.
You could compile java to js, but is a nightmare to debug and you are far away from the real code. You will have a lot of issues.
There are more benefits of js of course.
If you can't write your backend in something else and use the same devs, you have bad devs. It's not that hard to pick up a language if you understand the concepts needed to write a client and a server.
from my own experience, using single language has huge influence on overall code quality. Makes you understand it much better, comparing to situation you must switch between multiple languages. As you gain more experience in it, the less obvious bugs you'll make (just by knowing what's good and what's wrong).
The worst js code I see, is coming from programmers for whose javascript is their secondary (or third) language. They simply don't understand the basics of it. For example they use timeouts to make asynchronous code synchronous, etc... Then bitching on internet how bad language it is.
> from my own experience, using single language has huge influence on overall code quality.
From my experience, JS code is really poor quality and overly complex (looking at your build chain) even when written by an expert.
For me works amazingly. I couldn't see myself using anything else on server.
It's not hard to pick up a new language, but changing every 5 minutes it is, especially when you create a new feature.
I think I have 75% of the code shared between client and server side. Again, I can't see myself duplicating so much code and testing it.
I use typescript by the way, so it's pretty good imo.
Just think of all the utils that are shared between client and server side.
Of course I'm talking about web applications with streaming data, not simple webpages.
In a project before we had some functionally that was done on the client side, then somebody decided to move on the server side. Has to be written again in Java from scratch. It's doable, but it's more expensive.
Client- and server-side are very different in terms of network connectivity, CPU and other resources. On the backend you can get by with N+1 queries if the DB is running on the adjacent VM. On the client side, hardly.
Tools without flaws are not the tools that get used for real work. Sometimes you have to suck it up and learn the quirks in the tools you have.
That's not to discourage work on improving the current situation, just an observation on practicality.
I'm hoping WebASM can save the browser from this foul language. Don't even get me started on server-side JS; if it were a nice, sane scripting language, I'd agree, but the amount of hoops, translators, hackish dev tools etc that have been thrown into the mix to wrangle it into a workable experience... it's too much.
Arguably, such fracturing already exists with frontend frameworks. But what will that be like when we become fractured by language? Plenty of people like and prefer JavaScript, but seem to be at least as many people who would rather use an entirely different language on the frontend. I know someone will want to chime in and point out that WASM will still need to interact with JavaScript, but that's not really the point; once JavaScript as a language can be effectively ignored by the developer, that complicates our occupation in terms of interoperability.
One of the great things about web development was that workflows could be different but, at the end of the day, the end product is(was?) essentially HTML, CSS, and JavaScript. There were only so many languages we needed to learn in order to write servers, and at the end of the day we just needed to make something respond to HTTP requests. I chose web development because it wasn't going to pigeonhole me as much as other fields of software engineering; one can, or could, take their web development skills from one company and easily apply them to another, no matter the scale.
Today, we have a constantly evolving browser language, several frontend frameworks and rendering libraries, not just PHP; ASP; and Perl for the server but Python; Ruby; Java; Elixir; Node.js; Groovy, and a wide variety of toolchains and transpilation setups. Now, we're going to open the frontend floodgates to different language runtimes, and along with them even more frontend debugging tools?
This field is becoming way less fun. It's not that I don't understand the desire for choice or to simply not use JavaScript, but I doubt that as humans we won't naturally take the freedom given to us and use it to our detriment.
In practice, however, I think a lot of these things become irrelevant because JS subcommunities carve out reasonable subsets of the language. For example when using React you almost never need to care about prototypal (or even normal) inheritance because it's explicitly discouraged by React. And in the future, we might not need to encourage classes when writing components altogether.
If you limit yourself to avoiding some features then it's not such a bad language after all.
Unfortunately that's not possible unless you never interoperate with other code.
I also like the original practical vision for node.js/CommonJS as an escape from the metaprogramming excess that has become Java.
Javascript is a giant mess and all attempts to fix it seem to make it even worse. Having a sane language in the browser would be the single biggest boost to overall productivity. That alone would push the global gdp up by 5%. At the very least.