Skip to content

Instantly share code, notes, and snippets.

@nateabele
Forked from beardedtim/Posts.10.js
Last active March 20, 2019 20:47
Show Gist options
  • Save nateabele/eace26da2c7851086a5d18f45dda612c to your computer and use it in GitHub Desktop.
Save nateabele/eace26da2c7851086a5d18f45dda612c to your computer and use it in GitHub Desktop.
Forked in response to this article: https://medium.com/let-s-learn/lets-learn-composing-react-components-with-ramda-5db457997554 — I'm not sure I translated the code 100% correctly, but, you get the idea.
/**
* This is a forked and annotated example. I think it gets a lot of stuff right in terms
* of best practices on composition.
*
* There are a few things that I think could be better organized... that doesn't mean that
* the author is wrong; the things I'm calling out probably aren't even related to the point
* of the article.
*
* One of my issues with React is that it encourages decomposition for no good reason, which
* just makes your UI harder to maintain because you have to piece together dozens of tiny
* little functions in your head just to understand what a single logical interface element
* looks like and does.
*
* Deciding where to break things apart is just as important as deciding where to keep things
* together.
*/
// A single atomic unit of UI — this is good
const Comment = ({ text, author, _id }) => (
<div key={_id}>
<p>{text}</p>
<h5>{author}</h5>
</div>
);
// This is probably not worth calling out as its own thing, since you can easily inline it,
// and inlining it will probably lead to better code clarity
const CommentList = map(Comment);
const CommentWrapper = children => (
<div>
<h2>Comments</h2>
{children}
</div>
)
// This is nitpick, but Functor Laws say you can write `compose(map(x), map(y))` as
// `map(compose(x, y))`, which feels a bit less noisy
const wrapComments = compose(
map(CommentWrapper),
map(CommentList)
)
// These two don't really buy you much, IMO... just inline them
const getComments = compose(
wrapComments,
map(prop('comments'))
)
const CommentsWrapper = children => (
<div style={rowStyle}>
{children}
</div>
)
const wrapAllComments = compose(
CommentsWrapper,
getComments,
)
const Comments = compose(
wrapAllComments,
prop('posts')
)
/**
* Here's an example of the above that's functional but still cohesive.
*
* Still the same level of flexibility, and the composition is just
* as effective, but the flow is much clearer since we're not trying
* to do FP for its own sake, but mixing it effectively with the
* semi-imperative style that React forces on us.
*
* Using simple continuous left-to-right composition with the `pipe()`
* function, we can do a simple inline flow that only calls out to
* `Comment` and `CommentWrapper`, which are exactly the two atomic
* units of view code.
*/
const Comments = pipe(prop('posts'), (posts) => (
// This is even a bit superfluous. --^^-- You can just do `Comments = ({ posts }) => (`
<div style={rowStyle}>
{posts.map(pipe(
prop('comments'),
map(Comment),
CommentWrapper
))}
</div>
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment