DEV Community

loading...

Discussion on: React Is Eating Itself

Collapse
gsonderby profile image
Gert Sønderby

Good post! I largely agree with you, though I may myself be part of the anti-class/pro-hook cults in some capacity.

I really dislike the class keyword in JavaScript. It makes something messy (prototype inheritance) look neat but doesn't actually fix any of the messiness. It misleads devs into thinking it's well defined.

The namespace job you describe I generally use files or even directories for - a typical complex component of mine might have a couple files containing comonents, one or two files with hooks, and an index file that brings it all together. It typically contains zero class keywords, excepting any test assuring compatibility with class components.

Functions, meanwhile. JS is a function programming language with some other stuff attached. I've treated it like that for fifteen years now, and it's been extremely compliant for that time. Function purity is a useful concept, especially for certain modes of reasoning, but I will agree it's overvalued. React hooks are quite honestly a massive godsend here, and I will not be moved on that subject.

But apart from these opinions of mine, I feel you speak truth and I agree.

Collapse
bytebodger profile image
Adam Nathaniel Davis Author

It makes something messy (prototype inheritance) look neat but doesn't actually fix any of the messiness. It misleads devs into thinking it's well defined.

Not trying to argue, but I'm legitimately curious. Can you outline any scenarios where this theoretical "problem" actually leads to tangible problems? Like, have you ever seen a bug that would have been avoided if the developer hadn't "thought it was well defined"?

Every time I hear a JS dev rail against classes, it always seems (to my ear) to be tied almost entirely to theory with almost no basis in tangible effects. Specifically, it also sounds (to me) like, "This is the way that I think about the language. And anything that allows others to conceptualize it in another way is bad."

Many of the NPM packages we use have some very "messy" stuff under the hood. But when we use that NPM package, it's typically pretty simple for us to call a single function or drop a single component into our render() and suddenly we don't have to think about all the "messy" stuff. But I've never heard an anti-class person follow up their objection by saying that we should banish NPM.

Even in the scope of a single application: I figure out how to do <SomeComplexMessyThing>. Once I've solved that riddle, I package it into a function or component that can be used by anyone else working in the app. They just drop <SomeComplexMessyThing> into their new code and... it works.

In theory, it'd be great if everyone understood all of the underlying "stuff" that was happening with the components/functions/packages/libraries that they were importing. But that's just not realistic.

And finally: This is... "good"?

const foo = {
   name : 'george',
   age : 42,
   sayHello : () => console.log('Hello');
};

But this is... "bad"???

class foo {
   name = 'george';
   age = 42;
   sayHello = () => console.log('Hello');
}

Again, I'm not trying to argue about anything. I'm just legitimately curious (and confused). After reading thousands of words about the "evil" class keyword on the internet, and hearing similar sentiments from other devs in-person, I'm still waiting to hear an empirical answer, from anyone, that explains why class is somehow "wrong".

Collapse
gsonderby profile image
Gert Sønderby

Actual bugs? Not on my own watch, no. But I have seen juniors with some extremely wrong ideas about how classes work in JS, which hampered them. The class keyword is syntactic sugar, as you know - by itself not a bad thing. However, it obscures things - and it makes people think in ways that cause them problems when easier solutions are available.

Your second example isn't bad - but for proper equivalence the first one would have to look like this:

function foo() {
  this.name = "george";
  this.age = 42;
  this.sayHello = () => console.log("Hello")
}

Then you can new either one and get an instance.

Now what happens when Fred the Junior goes const bar = new foo(); bar.sayHello = () => console.log('Begone'); bar.sayHello();? Probably what he expected. But then Andy the Junior goes delete bar.sayHello(); because he needs that to not be present, and... Well, that didn't go to plan.

Consider this instead:

const foo = () => ({
  name: "george";
  age: 42;
  sayHello: () => console.log("Hello")
});

A simple factory function, same outcome as your top example except you can get more of them. Results are a lot easier to reason about, what you see is what you get, there's no secret machinery in the engine.

I'm just not aware of any advantage of classes in JS that makes them, their pitfalls, and the wrong ideas they spawn, worth it.

Meanwhile, my last two years were spent building exactly the kinds of abstractions you speak of, and as I mentioned, no classes in there. None needed.