Easily create React components that are completely devoid of this
.
You might remember me as the psychopath who wrote Rethinking JavaScript: The complete elimination and eradication of JavaScript's this
Well, I'm back and this time I've got a new React Component for you!
But WHY, you ask angrily?
I subscribe to the Douglas Crockford way of thinking.
"There are a few (features) we know that are going to be bad. The worst is Class. Class was the most requested new feature in JavaScript. And all of the requests came from Java programmers who have to program in JavaScript and don't want to learn how to do that. So they wanted something that looks like Java so they could be more comfortable. Those people will go to their graves not knowing how misserable they are." - Douglas Crockford
And in the same way that Douglas Crockford found his programs improved when he stopped using this, I found this to be true in my code as well.
"I was very surprised to discover that my programs got better. It was not a hardship to not use
this
. It was actually a benefit. My programs got smaller and easier and you know, that's what we're all looking for" -- Douglas Crockford
Even so, I do understand that there is little chance of me changing your mind because...
"Programmers are as emotional and irrational as normal people. So when the solution finally arrives, most of us will reject it." -- Douglas Crockford
This isn't just some anecdotal statement. Crockford goes on to provide real world examples, such as...
"It took a generation to agree that GOTO was a bad idea. We argued passionately, emotionally for 2 decades about whether we should use GOTO or not." -- Douglas Crockford
Well, this
is the GOTO
of JavaScript and I understand that it's not going to go away overnight. But I would like to hope that it won't take us two decades like GOTO
.
What does this all mean for React Components?
React does have a functional component, but React's most popular way of creating components is to create a class and extend from React.Component
and a Class
comes with this
.
Then I asked myself, what if I could use React.Component
but without this
. And that is how NoThis.Component
was born.
You'll notice NoThis.Component
is used in a way familiar to React.Component
. The context you would previously access via this is available as the first function argument.
import React from 'react'
import NoThis from 'nothis-react'
class Counter extends NoThis.Component {
state = { count: 0 }
increment(ctx) {
ctx.setState(state => ({ count: state.count + 1 }))
}
render(ctx) {
return (
<div>
<button onClick={ctx.increment}>{ctx.state.count}</button>
</div>
)
}
}
increment
and render
have become pure functions, acting only on their inputs!
Argument Destructuring
If you love destructuring as much as I do, then code like this now becomes possible!
import React from 'react'
import NoThis from 'nothis-react'
class Counter extends NoThis.Component {
state = { count: 0 }
increment({ setState }) {
setState(({ count }) => ({ count: count + 1 }))
}
render({ increment, state: { count } }) {
return (
<div>
<button onClick={increment}>{count}</button>
</div>
)
}
}
Now that is some sexy code.
Excluding Functions
A function can be excluded from nothis
by writing it as a class property.
class Counter extends NoThis.Component {
increment = () => {
this.setState(({ count }) => ({ count: count + 1 }))
}
}
Wrapup
This is some experimental future code, so treat it as such. Please do play with it and report any bugs or request features at the Github repo.
Join the #nothis
movement and hit me up on the tweety.
If you hated this article, you might also hate these too:
- I ❤ Ramda - Partial Application with a Special Placeholder
- Functional Programming: Alternatives to the IF #Functional #JavaScript #Functors
- Keep your code dumb
#nothis
Top comments (9)
Fat arrow functions make old complaints about "this" moot, especially in React. Instead of
simply do:
Benefits:
#thisIsFine
This is absolutely a fantastic solution and it definitely solves one of
this
's problems. This is a perfect example of that.I still prefer to eliminate
this
completely. I don't want to have to ask if the function has been written correctly so thatthis
behaves the way I expect it.I don't have to worry about "it's okay to use here, this way, but not over here." It's easier for me to program without it.
It's much like
null
. An even simpler concept thanthis
. We know to put nullchecks all over.But no matter how hard we try, we are still destined to run into
NullReferenceException
.And much like Douglas Crockford says...
... banning
this
in your programs, much likenull
won't be a hardship. It will become a benefit, making your programs smaller and easier!The only way to eliminate 100% of
this
related bugs, is to eliminatethis
.Cheers!
Unfortunately, this code is not idiomatic as you should pass a function to the setState in this case or else from several increments in a row most get ignored as the state is updated asynchronously and they will have a stale state... nothis FTW is what I take feom this comment in the end...
How do I add properties dynamically to
this
, taking an example from React docs on refs.If you say use
ctx
to dynamically attach things, that would just be no better thanthat = this
and defeat the whole point you are making.increment
is not pure since it mutates non-local state.I was writing React when I authored this tweet. I know it’s a controversial subject but I’m right there with you.
Haha! I don't know whether I should laugh or cry :)
recompose + @hocs/with-lifecycle provides more smooth solution than this one :)
I will totally agree with you on this. These both provide a very elegant functional design and if I start a project from scratch, I'll probably go with one of these. Sometimes the the code style is out of our control and not all developers are up to speed with FP.
The intent of
<NoThis.Component />
is not to push an FP paradigm. It's only purpose is to promotethis
to a function argument.I wouldn't say recompose is a better solution than @hocs/with-lifecycle or vice versa. They both have their place. At the same time I feel like this library also has it's place.
Cheers!