Enter Your Email Address to Watch This Lesson

Your link to unlock this lesson will be sent to this email address.

Unlock this lesson and all 1083 of the free egghead.io lessons, plus get React content delivered directly to your inbox!



Existing egghead members will not see this. Sign in.

Add Lifecycle Hooks to a Functional Stateless Component using Recompose

2:56 React lesson by

Learn how to use the 'lifecycle' higher-order component to conveniently use hooks without using a class component.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

Learn how to use the 'lifecycle' higher-order component to conveniently use hooks without using a class component.

Avatar
Tim

I updated the example to use the state property instead of getInitialState method because Recompose updated their library to remove all usages of React.createClass.

Avatar
Marc

Could you please explain the benefit of doing it this way instead of using React.Component?

I'm going to write a higher-order component called withConfig, and it's going to use the lifecycle higher-order component from Recompose. It's essentially an escape hatch to the full React.createClass API except for the render method, which is not allowed.

const withConfig = lifecycle({

});

I'm going to listen on componentDidMount, and the point of my withConfig higher component is to fetch a configuration. I'll listen on this configPromise, which contains the data I need, and then I'll setState to the config.

const withConfig = lifecycle({
    componentDidMount() {
        configPromise.then(config =>
            this.setState({ config }));
    }
});

It's important to note that anytime you use setState inside of lifecycle, the state actually gets converted to props when it gets passed into the wrapped component. I'll show that more in a second. I'm also going to use getInitialState, so that I can return an empty config.

const withConfig = lifecycle({
    getInitialState() {
        return { config: {} },
    },
    componentDidMount() {
        configPromise.then(config =>
            this.setState({ config }));
    }
});

I've mocked out a configuration, so I just need to call this fetchConfiguration method, and it's going to return to me this config object, but currently turned on because I'm actually passing them in as props to my dumb App component.

const config = {
    showStatus: true,
    canDeleteUsers: true
}

function fetchConfiguration() {
    return new Promise((resolve) => {
        setTimeout(() => resolve(config), 300);
    });
}

I'd like to be able to delete these showStatus and canDeleteUsers props in App completely and just have my configuration take care of it. Now they're gone, and we'll replace it with my higher-order component. Let's make a call to fetchConfiguration and store it in the configPromise that my componentDidMount lifecycle hook is listening on.

const configPromise = fetchConfiguration();

I want to make sure this is only called once for the entirety of my application. That way, if multiple components use this higher-order component, they won't each trigger a network call. That's why I do it outside of the higher-order component.

Now I'm going to wrap User in the withConfig higher-order component. I'm going to replace these showStatus and canDeleteUsers with just config, which we're getting from this setState call. Which as you remember gets passed in as a prop, not as state, since functional stateless components don't have state.

const User = withConfig(({ name, status, config })
    <div className="User">
        { name }
        { showStatus && '-' + status }
        { canDeleteUsers && <button>X</button> }
    </div>
);

Now, on the config, there's a showStatus, so I'm going to prepend config. in front of that. There's also a canDeleteUsers, so I'm also going to prepend config. there as well.

const User = withConfig(({ name, status, config })
    <div className="User">
        { name }
        { config.showStatus && '-' + status }
        { config.canDeleteUsers && <button>X</button> }
    </div>
);

It should be able to refresh, and we have our options back. We can now change them, and we can see that they're going away.

Options

Lastly, I just want to note that any hook can be used here as I had said. That includes things like shouldComponentUpdate, or componentWillMount, etc.



HEY, QUICK QUESTION!
Joel's Head
Why are we asking?