React Native’s base set of components are amazing! <View>
enforcing flexbox
and defaulting to {flexDirection: 'column', position: 'relative'}
? So smart.
It is such a successful set of components and constraints that web developers (like me) are bringing them to the web. See react-native-web and react-primitives for two great examples of this.
Now, this is getting a bit nitpicky, but I believe there is a good case for adding just a couple more layout components to your toolkit. Whether these components should exist at the framework, primitive level or in user-space is up for debate.
Given what we know about View
…
ref
is one of two special props in React — the other being key
— because it isn't really a prop. Instead of being passed in to the associated component as a this.props.ref
, React snatches it up and uses it to associate a reference to the component's instance or DOM node.
Above example shows setting this.node
to the div
DOM node via a ref
callback. Note: the old ref
string way, <div ref='node' />
is deprecated; don't do it!
If it is placed on a primitive like <div ref={...} />
, it will give you the DOM node instance. If…
An “Immutable Component” is a component that, after rendering once, can not re-render (i.e. it has shouldComponentUpdate() { return false }
).
See this writeup if you’d like more information on shouldComponentUpdate()
Many of your components will need to live and respond to prop
or state
updates, but there are also likely components that are never updated. Perhaps it is a layout component used for spacing, or a header component with a fixed label. Why should these unchanging components re-render()
, slowing down the javascript thread? They shouldn't! They should be immutable components.
React’s mechanism to create immutable components is within a…
React.cloneElement() allows us to clone a runtime element
(not the class), and apply an enhancement to it.
The code above renders a div
with the onPress
wired up. It is a contrived example, as a we can just pass in an onPress
directly to the div
, but what if <Press_ />
computed something complicated, then translated the result to something div
could use? That is quite a powerful abstraction!
Also, this <Press_ />
component allows us to clearly separate concerns and reuse them on other elements. We might reuse our Press_
on an image
or span
, for example. …
A “Null Component” is a component that returns null
, and likely uses lifecycle hooks to make side effects.
(I got the name from this oooold issue)
Can you tell me which of these components renders nothing?
I can’t either. I need prior knowledge of the components, or I need to read through their implementation.
If you are familiar with React Router V4, you may know that it doesn’t render anything, but what if you could know without prior knowledge?
Aligning closely with the <Injector_ > naming convention, Null Components are denoted with a prefix and postfix _
(e.g…
“A Higher-Order Component”
What does that mean?
“Well, if a higher-order function is a function that takes a function and returns a new function as the result, then a higher-order component must be a component that takes a component and returns a new component as the result, right?”
That is often the community’s response, but isn’t that just a component with children? How about the description that “A Higher Order Component is just a React Component that wraps another one”?
Again, isn’t that just a component with children?
Fortunately, React’s Official Docs have been updated with a description that makes…
shouldComponentRerender()
PureComponent
a component with children
See this link for an always-current, potentially more dev-friendly read.
By default, when a component changes and re-renders, all components in its render()
are also re-rendered, and their subcomponents are re-rendered, and so on, all the way down. shouldComponentUpdate()
is a class-based lifecycle method that empowers developers to change the default of a component, and prevent re-rendering completely, or only enable it in certain cases.
Note: this hook is only available to class-based components, not Stateless Functional Components.
Performance!
The less code we run, the more performant it’ll be. In…
An injector component takes props, optionally computes new ones, then injects them into its child via React.cloneElement()
. Crucially, it also does not add any new components to the DOM. It only exists in React's virtual DOM.
In the prototyping framework, constelation, we use a LOT of injector components to abstract out logic and nicely separate concerns like style, animation, and interactions from our layout components. React Native has also used this pattern in TouchableWithoutFeedback.
Here is an example render using some injector components:
But here’s the thing, do you know which of these components are injectors? …
When I first learned about spreading props in JSX, I was thrilled! It is just so convenient to pass props with <MyComponent {...this.props} />
, and override props defined after the spread, like <MyComponent {...this.props} text='override text prop' />
. I knew it made for a great developer experience, but I always wondered if it came with a cost. How does React handle it? Does it affect performance?
Well, it took me far too long, but I’ve finally answered my questions. You’re welcome to play around with this code using Babel’s online repl.
Let’s start with our control.
Cool, this shows…