tldr; In this article we go through a timeline of React from composition point of view
React has so many ways to do the same thing that sometimes it can be overwhelming and in the quest of being a 10x developer we may miss out on the best way(s) to do something. It's good to be aware of what any pattern is trying to solve and what bargains did the pattern make in achieving something. Understanding this will not only help us with our decision making during the implementation but it has many other benefits as well.
Let's go through the history of React from composition point of view and get an idea of when and why different patterns/features were introduced.
Timeline of composition in React
- React first got introduced in 2013
- Way to create react component - React.createClass(…)
- Ways of composition: children, mixins
- JSX Namespacing - v0.11 (July 2014)
- Props spreading in JSX - v0.12 (Oct 2014)
- New way to create create react component - ES6 classes.. no mixing in ES6 classes to keep it closer to JS language - v0.13 (Feb 2015)
- DOM node refs, stateless functional components, React.Children.toArray & React.Children.map - v0.14 (October 2015)
- Higher order components pattern officially introduced and mixins considered harmful- (July 2016)
- Render props pattern pushed by influential people, officially included in React docs (2017) New lifecycles, Fragments, Context API(stable) - v16 - (September 2017 - present)
- Hooks - future
Now let's get into some detail
Children
This is the way we've been composing elements even in plain HTML. React just took it further with JSX and applied similar concept with components. This is the most primary way to compose components.
Mixins
This was like the old school way to composition. They were considered good for quick bootstrapping and was very popular with jQuery. But React team has always been in favour of using functional composition. They even went on to write about why mixins are harmful. Anyways this was one of the most popular way to compose with React.createClass
syntax along with children
for a long time.
JSX Namespacing
It just helps if you can group related components under single namespace like this:
<Modal>
<Modal.Header>Title</Modal.Header>
<Modal.Body>Content</Modal.Body>
<Modal.Footer>Actions</Modal.Footer>
</Modal>
Props Spreading
After ES6 spread and rest operator came along, React just had to introduce this in JSX as well. It helps so much to pass only concerned props in a hierarchy of components. Consider this hypothetical example:
const Page = ({margin, ...props}) => <Box {...props} m={margin} />
React.Children.toArray & React.Children.map
These methods are helpful when you want to do some operations on children in an imperative way. Typically on componentDidMount
, you may want to loop through all the children and add some prop. However this isn't a very declarative approach as advised in functional paradigm. Also, it places a structural constraint that .map
only goes through children
and not the whole sub-tree.
DOM node refs
This is the getElementById
of React. You may not need this ever but some rare situations may require you to use refs. React added a better way to add refs in 16.3, React.createRef()
Higher Order Components and Render-props patterns
Much has been talked about these patterns everywhere so I won't go in detail. Anything that can be done using HOC can also be achieved via Render props and vise-versa. HOC came first, then came its some small disadvantages, which was followed by render-props pattern and then everything was rewritten in render-props. In the end these are just tools. Just pick one which fits your need.
Context API
Context has been used by libraries like Redux, styled-components, etc which we have been using at work. With the official context API by React in 16.3, it is even easier. Context used along with render-prop/HOC/hooks can produce some of the most beautiful APIs and easy to use components. However, you should be careful while using same context spreaded in the whole application. It should be used in closed scope and the user of your component shouldn't be concerned about what pattern you're using underneath.
Hooks
This is the future of React patterns. I'm yet to play around with it but it looks very promising. I can easily foresee everything being rewritten in it.
Conclusion
Having all these methods at one place helps us get a bigger picture of how composition can work in React. It also gives us the ability to pick a composition pattern depending on the problem statement at hand.
Top comments (4)
I'd also like to add to DOM node refs that one can use
refs
for "most cases" instead of using findDOMNode.Thanks I'll add that :)
:awyeah: 🙂
Good article!
Also, I think JSX Namespacing is more likely called Compound Components Pattern.