Recompose to Simplicity and Beyond

Timo Obereder speaking at React Vienna in June, 2017
437Views
 
Great talks, fired to your inbox 👌
No junk, no spam, just great talks. Unsubscribe any time.

About this talk

An overview of higher order components and how they're built. Plus, find out what Recompose is and what interesting stuff you can do with it.


Transcript


- Yeah, welcome everybody to this interesting talk. My name is Timo. I'm Android Native developer and also web developer with React. Today, I'm gonna talk about a library called Recompose. Basically, I will go through three subtopics in this presentation. The first one will be about the concept of higher order components. Then, I'm gonna show you in some practical examples how they are basically built with presentational component, container components. Then, Recompose. Yeah, let's get a little bit more serious. So higher order components. Which of you already have heard of higher order components or used them? So about 40%? Okay. Which of you have seen the movie Judge Dredd? Okay, 10%. Yeah, so basically, higher order components are components that, yeah, that are... Or higher order components are functions that take components, and in return you get, more or less, an enhanced component. This could either look like this that you... Pretty simple. You pass a component; you get back with an enhanced component. It could also look like this. You have one or two arguments and the component, then you get back the enhanced component. Or it could look like this, that you curry your properties or props further. So you say you have like two arguments, and you curry them on with the lambda operator, defined here, to a function that is returned that also has a property, which is the component. Then, you get back the, more or less, the operation which is the enhanced component. Which brings me to a side topic in this presentation. I will just shortly mention it that, yeah, this exists in functional concept, curry and partial application. So basically, a partial application is that... I'll just show you with the example that you... If we would have like an add function, which, yeah, adds two props, and you would partial this function... You could only pass like one parameter, but if you only pass one, then you get back an add function that still has one parameter left. And currying is basically... You have a function with n arguments, and what you want to do in currying is that you will turn this into n functions with one argument. In JavaScript, before ES6, this could have looked like this, that you have your function, you pass your first property, then you get your return function inside that function that also has a property. From this function you get a return operation which is the comparison between those values, so when you pick a limit. In ES6, with currying, of course since we only can pass one property, this would have looked like this that you see. You pass the limit, then the value, and then you finally get back the operation itself. Which brings me also to two examples of something to show you, basically. Everyone has used Redux probably, or most of us here in the room. You have a connect function, and this connect function takes two functions, one is the mapStateToProps, and one is the mapDispatchToProps function. And then, you curry that on to the component, and then you get back enhanced component. And this is basically this, right? There's another library called Relay if you want to do GraphQL requests. You have a createContainer function that takes a component. In this case, it's named "Todo." And the second argument is a... Basically, you want to map your requested data to an object called "Todo." And this is exactly this one, right? If you think back about functional concepts, function composition is nothing else than what higher order components tell us. We combine simple functions, and in return, build more complicated ones, right? But yeah, what is the purpose of this, all right? In the practical examples I will show you... First, I'll show you the presentational component itself, or presentational layer. And my understanding of that is that you basically declare a stateless functional component which just renders your JSX syntax and has maybe some properties. In this case, an SHA hash and a message. Then, if we go on and create our container, React component, this is basically what adds the functionality around this stateless functional component itself. So we can declare our state. We have our lifecycle component and mount function. If we got all the data, we render it in our stateless functional component. But we can abstract this a little bit further. We can say, "Okay, we wrap this whole thing "into a function called 'fetchCommit,'" and make this a little bit more dynamic. So we pass, basically... We could pass a different component, named "WrappedComponent", and then render this but with the same functionality, of course. And then, we can abstract this further. We can say, "Okay, we changed the name of this function "and call it 'fetchResource' and we pass the fetch function with a different path probably, and curry that onto a return function with the WrappedComponent. Then, basically, we get back the container component. In this case, I still have a fetch like the commits data. I mean, this is all just theoretical here on the slides, but we could change it. We could change the path of the fetch function, say, "Okay, we want all GitHub owners in a specific range, and then we render that in our "Owner" component. That brings me to two further small topics. One is the props proxy pattern where we basically can say we have our wrapper function, or higher order component now, where before we render anything, we create a new object that is named "user," and we pass it onto our wrapped component. So this is basically props manipulation. Then, another thing is inheritance inversion which kind of an antipattern. Maybe I shouldn't have showed it in the slides, but who cares in this case? And we have our wrapper function where we, instead of extend our React component, we extend the component we passed and render the parent's render function. How could we use that? Maybe for authentication logging where we say, "Okay, if the user's logged in, "then we want to render the render function "of the wrapped component. "And if he's not logged in, then we show nothing, "or we render something else." Yeah, that's basically render hijacking. There's also another thing where you can say, "Okay, if you render the parent's render function, "then before that, you can stringify props and state." And this is basically state manipulation. In context, or in conclusion, what can we do with higher order components? We can do a lot of code reuse. We can do logic and presentational layouts abstractions. We can do props manipulation and state abstraction which is with the props proxy pattern. And render hijack and state manipulation which is shown with the inheritance inversion. This is the last before I go to Recompose. Basically, what we're gonna do now is, if we have a stateless functional component, we wanna wrap that in functionality. So we have our first higher order component, or wrapper function that wraps functionality about our base component, and then our second and third. But in this case it looks pretty shitty, right? You could do this also with ES7 decorators, which would be like with @ annotations, and then define your base component or stateless functional component. But in this case, it would look much better if we would have a function that composes everything with that. So we have like our first H-O-C, and then the second and the third. In this case, I did it in reverse because most compose functions, I think, take the function on the far-most right and then it goes until to the left. Yeah, this is how a compose function could look like, but you can look at it later, if you're interested, on the slides. Yeah, Arnold is still not happy about it. At least he's a little bit more interested. What is Recompose? Recompose is a utility belt for function components and higher order components. At least that's what Andrew Clark defines. And what I see is wrapper functions. So we could declare a state for a stateless functional component, or handler functions, or we could rerender something if a property had changed, or if one or more properties, say, we could do something with PropsOnChange, or if we want to add lifecycle functionality then we could add that too. And many, many more. I'm gonna show you three more examples before our live code demo. First is the withState. So how do we define it, actually, in Recompose? If you look at the withState function, you see that the first argument is basically the name of your state. The second is the setter function. The third defines actually what your state will be like. Will it be a number? Will it be an empty string? Will it be a boolean object array? Or whatever. When I look down beneath, I composed this with counter state function, which is my state wrapper function. So now I can use that in my stateless functional component as normal property, the state and the setter function, and count up or count down my counter component. But I could abstract this, of course, a little bit more further. If I don't want to redeclare all the setter functions again and again, I could write handle functions which define a count up or a count down. So this looks a little bit more easy to read, I would say, instead of just defining the whole thing in your setter functions. And then another thing... shouldUpdate, as I said, if some property would change, for example, in this case, a property called "commitsMax" and a property that is something else... If those change, then it will return true and your stateless functional component would rerender. If it's false, then yeah, it would not. And yeah, it's pretty cool. It's a long animation. I'm sorry about that. Okay, so to get back, what are the pros and the cons? The pros are you have, of course, decouple functional and presentational layers. You could have faster development. You could improve refactoring if you know how yo If you have a good structure in your project. And of course, what for me, at least, was the most better experience for Recompose is that it's more readable. And the contras, of course. Expensive to change if the abstraction's wrong. Could be complex to newcomers. And it can be complex in computation because if you have your stateless functional component and you just have like 10 wrapper functions at the end, then a whole lot of objects will be created. And that brings me to the code demo. So if we start that thing and reload this page you can see we have like... Or what this application basically does is that I get my GitHub owner and I want to search through my repositories. If I type in, for example, the "react-recompose" example and press enter, it loads all the, or the last five, commits of this repository, and shows the SHA key and the message to it. Or something else. I did some error handling too, which is pretty simple. So if I would type anything that it would return nothing because this repository doesn't exist. Just to show you that it really works; and another repository. So yeah, it requests the repository data from GitHub. And if we look inside of the code, this project is built with Webpack 2, ES6 code, and of course Recompose. If we look into the first index.js, you can see I'm using Apollo Client to fetch the data and defining where I have to wrap my data. And then I have a root component. - [Audience Member]increase the font-size? It's not - Oh sure. Sorry. Better? - [Audience Member] Way more. - Yeah? - [Audience Member] Yeah. No, no. You need way more. - Way more. Okay. Okay. - [Audience Member] 10 times. - More? - [Audience Member] Way more, yeah. That's good. - Yeah? Okay. What the fuck? Okay. Yeah, where was I? Yeah, root component. Root. So I created a root component which defines with React Router, of course, which routes I call and where. And I have two main components. One is the Search component you saw when I was searching some stuff. And the Commits component which shows actual the list of the grabbed data. If I look into the structure and go into the Search component, you can see I defined the compose function of Recompose, the withState, and the withHandlers function. And I defined withState for my component and I also can give it another name. You can also write this withState, for example, inside the compose function itself, but if you define everything down there it look a little bit messy. I just like this approach better. So everything's functional. Everything's nice and clean. And then we define a handle function where I actually take every input of my input field and pass the value of that input field into my repo state. And yeah, of course the second one is just the... When I press the enter key, or yeah, I also can click the name down below if I don't want that. And it looks pretty nice. And if we do that, then what happens... It gets into the Commits component where I have my query for the GraphQL request where it takes my owner, my repo. It goes to GitHub to the repository that's defined of the owner of the repo and takes the maximum of five commits and the SHA and message. And then, of course, with the query itself I grab the data and want to map it onto props. And of course, if I don't want to wait too long for the data to be grabbed and see nothing, so I show a withLoading function. And yeah, of course, if something goes wrong, I just return a "repository does not exist." In the end, as you see, even though these are not Recompose functions, I still can compose all other functionality in it. So this is pretty nice. In the end, I just wrote a renderCommits function that maps through the grabbed commits data, and I render a stateless functional component without anything in it except the render stuff. Go back to this nice presentation? What happened? - [Helper] Just keep it that way, otherwise the video- - Okay. - [Helper] The video will break. - Okay. I'm sorry. So yeah, if you want to grab that repository to try out things, you can... Or you feel free to do so. If you're interested in setting up Webpack 1, you can read my article from last year. I still didn't update it for the Webpack 2 configuration, but I will eventually put it on medium somewhere when I'm ready. Take everything except my soul. Thanks for listening, and yeah.