While I am in a tidying mood, that ConnectedPost looks a lot like boilerplate. Surely we can extract some of that away?
Here’s how it looks now.
export default class ConnectedPost extends React.Component { constructor(props) { super(props) this.state = { post: {} } } render() { const {post} = this.state return <Post post={post} /> } async componentDidMount() { const post = await fetchPost(1) this.setState({post}) } }
It’s all just xxxxx post xxx Post …..fetchPost. Maybe that’s the start of a framework? Let’s try a higher-order component (HOC) the way that Redux does for connected components.
I want a function that will wrap my Post component and call fetchPost when it mounts. I’ll call it like this:
export default connect(Post, fetchPost)
I don’t know how to do this incrementally so I’ll just go for it.
import React from 'react' export function connect(WrappedComponent, fetch) { return class extends React.Component { constructor(props) { super(props) this.type = WrappedComponent.name.toLowerCase() this.state = { model: {} } } render() { const props = { [this.type]: this.state.model } return <WrappedComponent {...props} /> } async componentDidMount() { const model = await fetch(1) this.setState({model}) } } }
It does exactly the same as it did before except, now it will do it for any model-view-api, not just for Posts.
Wait! What is that “1” doing in there? That could just be a property on the WrappedComponent.
async componentDidMount() { const model = await fetch(this.props.id) this.setState({model}) }
While we are here, api.js is a bit boilerplatey too. Can we can use convention-over-configuration to fetch models too?
We can. All of my rails routes take the form `/:pluralized_model_name/:id’. Let’s use that to make a generalized fetch() function.
import {server} from 'remote/server' export function fetch(type, id) { return server.send(urlFor(type, id)) } function urlFor(type, id) { return `/${type}s/${id}.json` }
And we can call it with…
async componentDidMount() { const model = await fetch(this.type, this.props.id) this.setState({model}) }
I think that’s enough tidying for now. Let’s get back to building features for our blogging platform.